A toggle button component for selecting one or multiple options from a button group
npm install @choice-ui/toggle-buttonA controlled toggle button component that switches between two states with visual feedback. Perfect for binary controls, feature toggles, and state indicators.
The ToggleButton component provides a button that maintains an active/inactive state, typically used for toggling features, settings, or modes. It requires controlled state management and supports multiple variants and sizes.
``tsx
import { useState } from "react"
import { FieldAdd, FieldTypeCheckbox } from "@choiceform/icons-react"
import { ToggleButton } from "~/components/toggle-button"
export function BasicExample() {
const [isToggled, setIsToggled] = useState(false)
return (
value={isToggled}
onChange={setIsToggled}
>
{isToggled ?
)
}
`
`tsx
export function VariantsExample() {
const [states, setStates] = useState({
default: false,
secondary: false,
highlight: false,
})
const toggle = (key: keyof typeof states) => {
setStates((prev) => ({ ...prev, [key]: !prev[key] }))
}
return (
variant="secondary"
value={states.secondary}
onChange={() => toggle("secondary")}
>
variant="highlight"
value={states.highlight}
onChange={() => toggle("highlight")}
>
$3
`tsx
export function SizesExample() {
const [isToggled, setIsToggled] = useState(false) return (
aria-label="Small toggle"
size="small"
value={isToggled}
onChange={setIsToggled}
>
aria-label="Medium toggle"
size="medium"
value={isToggled}
onChange={setIsToggled}
>
aria-label="Large toggle"
size="large"
value={isToggled}
onChange={setIsToggled}
>
)
}
`Props
| Prop | Type | Default | Description |
| ------------ | ----------------------------------------- | ----------- | --------------------------------------------- |
|
value | boolean | - | Required. Current toggle state |
| onChange | (value: boolean) => void | - | Required. Callback when state changes |
| aria-label | string | - | Required. Accessible label for the button |
| variant | "default" \| "secondary" \| "highlight" | "default" | Visual style variant |
| size | "small" \| "medium" \| "large" | "medium" | Button size |
| disabled | boolean | false | Whether the button is disabled |
| className | string | - | Additional CSS classes |
| children | ReactNode | - | Button content (usually icons) |Variants
$3
Standard toggle button with accent coloring when active.
`tsx
variant="default"
value={isActive}
onChange={setIsActive}
aria-label="Default toggle"
>
`$3
Subtle styling with muted colors for secondary actions.
`tsx
variant="secondary"
value={isActive}
onChange={setIsActive}
aria-label="Secondary toggle"
>
`$3
Prominent styling for important toggles that need attention.
`tsx
variant="highlight"
value={isActive}
onChange={setIsActive}
aria-label="Highlight toggle"
>
`Sizes
$3
Compact size for dense layouts or secondary actions.
`tsx
size="small"
{...props}
>
`$3
Standard size for most use cases.
`tsx
size="medium"
{...props}
>
`$3
Larger size for prominent controls or touch interfaces.
`tsx
size="large"
{...props}
>
`Advanced Examples
$3
`tsx
import { useState } from "react"export function FeatureToggleGroup() {
const [features, setFeatures] = useState({
darkMode: false,
notifications: true,
autoSave: false,
soundEffects: true,
})
const toggleFeature = (key: keyof typeof features) => {
setFeatures((prev) => ({ ...prev, [key]: !prev[key] }))
}
return (
Feature Toggles
aria-label="Toggle dark mode"
value={features.darkMode}
onChange={() => toggleFeature("darkMode")}
>
{features.darkMode ? : }
Dark Mode
aria-label="Toggle notifications"
variant="highlight"
value={features.notifications}
onChange={() => toggleFeature("notifications")}
>
{features.notifications ? : }
Notifications
aria-label="Toggle auto save"
variant="secondary"
value={features.autoSave}
onChange={() => toggleFeature("autoSave")}
>
{features.autoSave ? : }
Auto Save
aria-label="Toggle sound effects"
value={features.soundEffects}
onChange={() => toggleFeature("soundEffects")}
>
{features.soundEffects ? : }
Sound Effects
)
}
`$3
`tsx
import { useState } from "react"export function ToolbarExample() {
const [formatting, setFormatting] = useState({
bold: false,
italic: false,
underline: false,
strikethrough: false,
})
const toggleFormat = (key: keyof typeof formatting) => {
setFormatting((prev) => ({ ...prev, [key]: !prev[key] }))
}
return (
aria-label="Bold text"
size="small"
variant="secondary"
value={formatting.bold}
onChange={() => toggleFormat("bold")}
>
aria-label="Italic text"
size="small"
variant="secondary"
value={formatting.italic}
onChange={() => toggleFormat("italic")}
>
aria-label="Underline text"
size="small"
variant="secondary"
value={formatting.underline}
onChange={() => toggleFormat("underline")}
>
aria-label="Strikethrough text"
size="small"
variant="secondary"
value={formatting.strikethrough}
onChange={() => toggleFormat("strikethrough")}
>
)
}
`$3
`tsx
import { useState } from "react"export function ViewModeExample() {
const [viewMode, setViewMode] = useState<"list" | "grid">("list")
return (
aria-label="List view"
variant="secondary"
size="small"
value={viewMode === "list"}
onChange={() => setViewMode("list")}
>
aria-label="Grid view"
variant="secondary"
size="small"
value={viewMode === "grid"}
onChange={() => setViewMode("grid")}
>
{viewMode === "list" ? (
List Item 1
List Item 2
) : (
Grid Item 1
Grid Item 2
)}
)
}
`$3
`tsx
export function DisabledExample() {
const [isToggled, setIsToggled] = useState(true) return (
aria-label="Disabled toggle"
value={isToggled}
onChange={setIsToggled}
disabled
>
This toggle is disabled and cannot be changed
)
}
`Accessibility
$3
- Space/Enter: Toggle the button state
- Tab: Move focus to/from the toggle button
- Proper focus indicators for keyboard navigation
$3
-
aria-label is required for accessibility
- Button role automatically provided
- State changes announced to screen readers
- Pressed state communicated via aria-pressed$3
1. Always provide
aria-label: This is required for screen reader users
2. Clear state indication: Use visual changes that don't rely only on color
3. Consistent behavior: Toggle buttons should behave predictably
4. Group related toggles: Use proper semantic grouping for related controlsStyling
The ToggleButton component supports:
- CSS custom properties for theming
- Tailwind classes via
className prop
- Variant-based styling system
- Size-based scaling
- State-based visual feedbackCommon Patterns
$3
`tsx
id="feature-toggle"
aria-label="Enable feature"
value={enabled}
onChange={setEnabled}
>
{enabled ? : }
`$3
`tsx
const [selected, setSelected] = useState('option1')
{['option1', 'option2', 'option3'].map(option => (
key={option}
aria-label={Select ${option}}
value={selected === option}
onChange={() => setSelected(option)}
>
{option}
))}
`Migration Notes
If migrating from other toggle components:
- Ensure
aria-label` is added (required)