- Alert
- Avatar
- Badge
- Breadcrumb
- Button
- Button Group
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Checkbox Group
- ComboBox
- Command
- Data Table
- Date Field
- Date Picker
- Date Range Picker
- Dialog
- Disclosure
- Disclosure Group
- Drawer
- Empty
- Field
- File Trigger
- Form
- Grid List
- Hover Card
- Input
- Input Group
- Input OTP
- Item
- Kbd
- Label
- ListBox
- Menu
- Number Field
- Pagination
- Popover
- Progress Bar
- Radio Group
- Range Calendar
- Resizable
- Search Field
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Spinner
- Switch
- Table
- Tabs
- Tag Group
- Text Field
- Textarea
- Time Field
- Toast
- Toggle Button
- Toggle Button Group
- Tooltip
- Tree
- Typography
A toggle button allows a user to toggle a selection on or off, for example switching between two states or modes.
import { BoldIcon } from "lucide-react"
import { ToggleButton } from "@/components/ui/toggle-button"
export function ToggleButtonDemo() {
return (
<ToggleButton variant="outline" aria-label="Toggle bold">
<BoldIcon />
Bold
</ToggleButton>
)
}
Installation
pnpmnpmyarnbunpnpm dlx shadcn@latest add toggle-button
Usage
import { ToggleButton } from "@/components/ui/toggle-button"<ToggleButton aria-label="Toggle bold">
<BoldIcon />
</ToggleButton>Features
Toggle buttons are similar to action buttons, but support an additional selection state that is toggled when a user presses the button. There is no built-in HTML element that represents a toggle button, so React Aria implements it using ARIA attributes.
- Styleable – Hover, press, keyboard focus, and selection states are provided for easy styling.
- Accessible – Uses a native
<button>element with thearia-pressedattribute, and supports the Space and Enter keys to toggle the selection state. - Cross-browser – Mouse, touch, keyboard, and focus interactions are normalized to ensure consistency across browsers and devices.
Examples
Default
import { BoldIcon } from "lucide-react"
import { ToggleButton } from "@/components/ui/toggle-button"
export function ToggleButtonDefault() {
return (
<ToggleButton aria-label="Toggle bold">
<BoldIcon />
</ToggleButton>
)
}
<ToggleButton aria-label="Toggle bold">
<BoldIcon />
</ToggleButton>Outline
import { BoldIcon } from "lucide-react"
import { ToggleButton } from "@/components/ui/toggle-button"
export function ToggleButtonOutline() {
return (
<ToggleButton variant="outline" aria-label="Toggle bold">
<BoldIcon />
</ToggleButton>
)
}
<ToggleButton variant="outline" aria-label="Toggle bold">
<BoldIcon />
</ToggleButton>With Text
import { BoldIcon } from "lucide-react"
import { ToggleButton } from "@/components/ui/toggle-button"
export function ToggleButtonDemo() {
return (
<ToggleButton variant="outline" aria-label="Toggle bold">
<BoldIcon />
Bold
</ToggleButton>
)
}
<ToggleButton variant="outline" aria-label="Toggle bold">
<BoldIcon />
Bold
</ToggleButton>Size
import { BoldIcon } from "lucide-react"
import { ToggleButton } from "@/components/ui/toggle-button"
export function ToggleButtonSize() {
return (
<div className="flex flex-wrap items-center gap-2">
<ToggleButton variant="outline" size="sm" aria-label="Toggle bold">
<BoldIcon />
</ToggleButton>
<ToggleButton variant="outline" aria-label="Toggle bold">
<BoldIcon />
</ToggleButton>
<ToggleButton variant="outline" size="lg" aria-label="Toggle bold">
<BoldIcon />
</ToggleButton>
</div>
)
}
<ToggleButton variant="outline" size="sm" aria-label="Toggle bold">
<BoldIcon />
</ToggleButton>
<ToggleButton variant="outline" aria-label="Toggle bold">
<BoldIcon />
</ToggleButton>
<ToggleButton variant="outline" size="lg" aria-label="Toggle bold">
<BoldIcon />
</ToggleButton>Disabled
import { BoldIcon } from "lucide-react"
import { ToggleButton } from "@/components/ui/toggle-button"
export function ToggleButtonDisabled() {
return (
<ToggleButton variant="outline" isDisabled aria-label="Toggle bold">
<BoldIcon />
</ToggleButton>
)
}
<ToggleButton variant="outline" isDisabled aria-label="Toggle bold">
<BoldIcon />
</ToggleButton>Controlled
Status: Not favorited
"use client"
import { useState } from "react"
import { StarIcon } from "lucide-react"
import { ToggleButton } from "@/components/ui/toggle-button"
export function ToggleButtonControlled() {
const [isSelected, setSelected] = useState(false)
return (
<div className="flex flex-col gap-4">
<ToggleButton
variant="outline"
isSelected={isSelected}
onChange={setSelected}
aria-label="Toggle favorite"
>
<StarIcon className={isSelected ? "fill-current" : ""} />
Favorite
</ToggleButton>
<p className="text-muted-foreground text-sm">
Status: {isSelected ? "Favorited" : "Not favorited"}
</p>
</div>
)
}
"use client"
import { useState } from "react"
import { StarIcon } from "lucide-react"
import { ToggleButton } from "@/components/ui/toggle-button"
export default function Example() {
const [isSelected, setSelected] = useState(false)
return (
<ToggleButton
variant="outline"
isSelected={isSelected}
onChange={setSelected}
aria-label="Toggle favorite"
>
<StarIcon className={isSelected ? "fill-current" : ""} />
Favorite
</ToggleButton>
)
}A default selection state for a toggle button can be set using the defaultSelected prop, or controlled with the isSelected prop. The onChange event is fired when the user presses the button, toggling the boolean.
API Reference
ToggleButton
The ToggleButton component supports both uncontrolled and controlled states.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "outline" | "default" | The visual style of the toggle button. |
size | "default" | "sm" | "lg" | "default" | The size of the toggle button. |
isSelected | boolean | - | Whether the toggle button is selected (controlled). |
defaultSelected | boolean | false | Whether the toggle button is selected by default (uncontrolled). |
onChange | (isSelected: boolean) => void | - | Handler that is called when the selection state changes. |
isDisabled | boolean | false | Whether the toggle button is disabled. |
aria-label | string | - | A label for the toggle button (required if no visible text). |
Apart from the props above, the ToggleButton component also supports all props from the react-aria-components ToggleButton component. Check the React Aria documentation for more details.
Accessibility
If a visual label is not provided (e.g. an icon only button), then an aria-label or aria-labelledby prop must be passed to identify the button to assistive technology.
// Good: has aria-label
<ToggleButton variant="outline" aria-label="Toggle bold">
<BoldIcon />
</ToggleButton>
// Bad: missing label
<ToggleButton variant="outline">
<BoldIcon />
</ToggleButton>