Skip to content
UI

Toggle

A button that stays pressed or unpressed, for turning a view option on and off.

@zenoxai/ui/components/toggleBase UI Markdown
<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.

Refresh to see new alerts.
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> with aria-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.

PropTypeDefault
defaultPressedboolean

Whether the toggle button is currently pressed. This is the uncontrolled counterpart of `pressed`.

false
disabledboolean

Whether the component should ignore user interaction.

false
nativeButtonboolean

Whether 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.

-
pressedboolean

Whether the toggle button is currently pressed. This is the controlled counterpart of `defaultPressed`.

-
renderReactElement<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" | null

Height: `sm` 28px, `default` 32px, `lg` 36px.

default
valuestring

A 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