Toggle
A button that stays pressed or unpressed, for turning a view option on and off.
<Toggle aria-label="Pin alert">
<PinIcon />
</Toggle>Usage
import { PinIcon } from "lucide-react"
import { Toggle } from "@zenoxai/ui/components/toggle"
export function PinToggle() {
return (
<Toggle aria-label="Pin alert">
<PinIcon />
</Toggle>
)
}
Use a toggle for an option that changes how the current view looks or behaves: wrap long lines, hide resolved alerts, pin an item. It reads as a button with a pressed state, so it belongs in toolbars and table headers.
Use something else when:
- The option is a setting that persists, such as enabling notifications: use a Switch.
- The user picks one or more options from a set: use a Toggle Group.
- Clicking runs an action instead of changing a state: use a Button.
Examples
Outline
outline adds a border, so the toggle stands out next to text or on a busy surface. The
default variant has no border and suits icon toolbars. A third variant, segmented, is meant
for items inside a Toggle Group.
<>
<Toggle variant="outline" aria-label="Wrap long lines" defaultPressed>
<WrapTextIcon />
</Toggle>
<Toggle variant="outline">
<EyeOffIcon data-icon="inline-start" />
Hide resolved
</Toggle>
</>Sizes
sm (28px), default (32px) and lg (36px), matching the Button heights.
Mark an icon next to text with data-icon="inline-start" or data-icon="inline-end" to
tighten the padding on that side.
<>
<Toggle size="sm" variant="outline" aria-label="Pin alert">
<PinIcon />
</Toggle>
<Toggle variant="outline" aria-label="Pin alert">
<PinIcon />
</Toggle>
<Toggle size="lg" variant="outline" aria-label="Pin alert">
<PinIcon />
</Toggle>
</>Controlled
Pass pressed and onPressedChange when something else on the page depends on the state.
Use defaultPressed for an uncontrolled toggle that starts pressed.
function ToggleControlled() {
const [live, setLive] = React.useState(false)
return (
<div className="flex items-center gap-3">
<Toggle variant="outline" pressed={live} onPressedChange={setLive}>
<RadioIcon data-icon="inline-start" />
Live updates
</Toggle>
<span className="text-sm text-text-secondary">
{live
? "New alerts stream in as they arrive."
: "Refresh to see new alerts."}
</span>
</div>
)
}Disabled
A disabled toggle still shows whether it is pressed, so the user can read the state while the option is unavailable.
<>
<Toggle variant="outline" disabled>
<EyeOffIcon data-icon="inline-start" />
Hide resolved
</Toggle>
<Toggle variant="outline" disabled defaultPressed aria-label="Pin alert">
<PinIcon />
</Toggle>
</>Accessibility
- The toggle is a native
<button>witharia-pressed, so screen readers announce it as a toggle button and its state. Space and Enter change it. - Keep the label the same in both states (“Live updates”, not “Start” and “Stop”): the pressed state already tells the user whether it is on.
- An icon-only toggle needs an
aria-label.
API reference
Generated from the TypeScript source. className, style and children are accepted everywhere and omitted below.
Toggle
Toggle is a two-state button that stays pressed, such as Bold in a text toolbar or "Show archived" above a list. For several related toggles use ToggleGroup; for a setting in a form, Switch or Checkbox.
| Prop | Type | Default |
|---|---|---|
defaultPressed | booleanWhether the toggle button is currently pressed. This is the uncontrolled counterpart of `pressed`. | false |
disabled | booleanWhether the component should ignore user interaction. | false |
nativeButton | booleanWhether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (for example, `<div>`). | true |
onPressedChange | ((pressed: boolean, eventDetails: { reason: "none"; event: Event; cancel: () => void; allowPropagation: () => void; isCanceled: boolean; isPropagationAllowed: boolean; trigger: Element; }) => void)Callback fired when the pressed state is changed. | - |
pressed | booleanWhether the toggle button is currently pressed. This is the controlled counterpart of `defaultPressed`. | - |
render | ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, ToggleState>Allows you to replace the component's HTML element with a different tag, or compose it with another component. | - |
size | "default" | "sm" | "lg" | nullHeight: `sm` 28px, `default` 32px, `lg` 36px. | default |
value | stringA unique string that identifies the toggle when used inside a toggle group. | - |
variant | "default" | "outline" | "segmented" | null`default` is borderless; `outline` adds the border of an outline Button; `segmented` is an item of a segmented ToggleGroup. Every variant marks the pressed state the same way, with the selection colors (primary-soft fill and text) that FilterChip and the sidebar use, so pressed never looks like hover. | default |