Toggle
A button that stays on or off, with a fill that settles in when pressed, a clear hover-to-on step and icons that can fill with the state.
pnpm dlx shadcn@latest add https://hextaui.com/r/toggle.jsonAdds the component, the HextaUI theme tokens and any HextaUI components it depends on.
Add the theme tokens to your global CSS, if you haven’t yet.
Install the dependencies.
pnpm add @base-ui/react class-variance-authority cnCopy and paste the following code into your project.
components/ui/toggle.tsx Update the import paths to match your project setup.
Hovering an off toggle shows a light tint; turning it on settles a stronger fill into place and brings the label to full contrast, so on never looks like hover.
Outline
variant="outline" adds a border and a surface, for toggles that sit on their own.
With text
Icons and labels sit side by side. Toggles with visible text don't need an aria-label.
Filled when on
Add group-data-pressed/toggle:fill-current to an outline icon and it fills in as the toggle turns on.
Sizes
sm, default and lg. Icon-only toggles stay square.
Disabled
A disabled toggle keeps showing whether it's on, but can't be pressed or focused.
Controlled
Pass pressed and onPressedChange. The label stays the same while the icon follows the state.
Right to left
Icons lead the label from the right.
| Key | Action |
|---|---|
| SpaceEnter | Turns the focused toggle on or off. |
| Tab | Moves focus to the next toggle. |
- The toggle is a
buttonwitharia-pressed, so screen readers announce whether it's on. - Give icon-only toggles an
aria-labelthat names the action ("Mute microphone") and keep it the same in both states. Changing it as well as the pressed state reads as a double negative. - On touch screens the hit area grows to at least 44px, except inside a toggle group where neighbours would overlap.
- With reduced motion, nothing scales; the fill only fades.
| Prop | Type | Default |
|---|---|---|
variant | "default" | "outline" | "default" |
size | "default" | "sm" | "lg" | "default" |
pressed | boolean | – |
defaultPressed | boolean | false |
onPressedChange | (pressed, details) => void | – |
disabled | boolean | false |
valueIdentifies the toggle inside a toggle group. | string | – |
className | string | (state) => string | – |
nativeButton | boolean | true |
render | ReactElement | (props, state) => ReactElement | <button> |
| Attribute | Description |
|---|---|
data-slot="toggle" | The button, with data-variant and data-size. |
data-pressed | Present when the toggle is on. |
data-disabled | Present when the toggle is disabled. |