Toggle
A two-state button that turns a single option on or off and shows its current state.
import { BoldIcon, ItalicIcon, UnderlineIcon } from "lucide-react"
import { Toggle } from "@/components/ui/toggle"
export default function ToggleDemo() {
return (
<div className="flex items-center gap-1 rounded-xl border bg-card p-1 shadow-raised">
<Toggle aria-label="Bold" defaultPressed>
<BoldIcon />
</Toggle>
<Toggle aria-label="Italic">
<ItalicIcon />
</Toggle>
<Toggle aria-label="Underline">
<UnderlineIcon />
</Toggle>
</div>
)
}Installation
$ pnpm dlx shadcn@latest add https://www.prfct.dev/r/toggle.jsonUsage
import { Toggle } from "@/components/ui/toggle"<Toggle aria-label="Bold">
<BoldIcon />
</Toggle>Examples
Outline
The outline variant gives each toggle a visible boundary. Use it when toggles stand alone on a page rather than inside a toolbar.
import { EyeOffIcon, LockIcon, PinIcon } from "lucide-react"
import { Toggle } from "@/components/ui/toggle"
export default function ToggleOutline() {
return (
<div className="flex items-center gap-2">
<Toggle variant="outline" aria-label="Pin to sidebar" defaultPressed>
<PinIcon />
</Toggle>
<Toggle variant="outline" aria-label="Lock layer">
<LockIcon />
</Toggle>
<Toggle variant="outline" aria-label="Hide layer">
<EyeOffIcon />
</Toggle>
</div>
)
}With text
Pair the icon with a label when the icon alone could be ambiguous, or when the toggle is the only control of its kind on the page.
import { BellIcon, StarIcon } from "lucide-react"
import { Toggle } from "@/components/ui/toggle"
export default function ToggleWithText() {
return (
<div className="flex items-center gap-2">
<Toggle variant="outline" defaultPressed>
<StarIcon data-icon="inline-start" />
Starred
</Toggle>
<Toggle variant="outline">
<BellIcon data-icon="inline-start" />
Watch
</Toggle>
</div>
)
}Sizes
Toggles share heights with buttons and inputs — sm 32, default 36, lg 40 — so they align in any toolbar.
import { BookmarkIcon } from "lucide-react"
import { Toggle } from "@/components/ui/toggle"
export default function ToggleSizes() {
return (
<div className="flex items-center gap-3">
<Toggle variant="outline" size="sm" aria-label="Bookmark">
<BookmarkIcon />
</Toggle>
<Toggle variant="outline" aria-label="Bookmark">
<BookmarkIcon />
</Toggle>
<Toggle variant="outline" size="lg" aria-label="Bookmark">
<BookmarkIcon />
</Toggle>
</div>
)
}Controlled
Control the state with pressed and onPressedChange when something else on the page depends on it. Here the icon and the helper text follow the state.
You'll be notified about new comments.
"use client"
import * as React from "react"
import { BellIcon, BellOffIcon } from "lucide-react"
import { Toggle } from "@/components/ui/toggle"
export default function ToggleControlled() {
const [subscribed, setSubscribed] = React.useState(true)
return (
<div className="flex flex-col items-center gap-3">
<Toggle
variant="outline"
pressed={subscribed}
onPressedChange={setSubscribed}
>
{subscribed ? (
<BellIcon data-icon="inline-start" />
) : (
<BellOffIcon data-icon="inline-start" />
)}
Notifications
</Toggle>
<p className="text-sm text-muted-foreground" aria-live="polite">
{subscribed
? "You'll be notified about new comments."
: "You won't get notifications for this thread."}
</p>
</div>
)
}const [subscribed, setSubscribed] = React.useState(true)
<Toggle pressed={subscribed} onPressedChange={setSubscribed}>
{subscribed ? <BellIcon data-icon="inline-start" /> : <BellOffIcon data-icon="inline-start" />}
Notifications
</Toggle>Disabled
import { ItalicIcon } from "lucide-react"
import { Toggle } from "@/components/ui/toggle"
export default function ToggleDisabled() {
return (
<div className="flex items-center gap-2">
<Toggle aria-label="Italic" disabled>
<ItalicIcon />
</Toggle>
<Toggle variant="outline" aria-label="Italic" disabled defaultPressed>
<ItalicIcon />
</Toggle>
</div>
)
}Guidelines
When to use
- For formatting and view options that apply immediately: bold, italic, word wrap, grid lines.
- For marking something: Star, Pin, Watch — where the pressed state is the information.
When not to use
- For settings that take effect as a preference — use a Switch, which reads as on/off rather than pressed.
- For one choice among several — use a Toggle Group.
- To trigger an action that doesn't have a persistent state — use a Button.
Label the option, not the action
A toggle's label names what it controls and stays the same in both states. The pressed styling carries the state; changing the text as well makes people unsure which state they're looking at.
Accessibility
- Renders a native
<button>witharia-pressed, so screen readers announce it as a toggle button with its current state. - Icon-only toggles need an
aria-label. Don't include the state in the label — Bold, not Bold on — becausearia-pressedalready conveys it. - The pressed state is shown with a fill and a darker label, not by color alone; in forced-colors mode it takes the system's selection colors.
| Key | Behavior |
|---|---|
Tab | Moves focus to the toggle. |
SpaceEnter | Toggles the pressed state. |
API reference
Toggle
Renders a <button>. Accepts every prop of Base UI's Toggle.
toggleVariants
The class generator, exported so other elements — like Toggle Group items — share the same styles.