Toggle Button

PreviousNext

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

pnpm 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 the aria-pressed attribute, 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.

PropTypeDefaultDescription
variant"default" | "outline""default"The visual style of the toggle button.
size"default" | "sm" | "lg""default"The size of the toggle button.
isSelectedboolean-Whether the toggle button is selected (controlled).
defaultSelectedbooleanfalseWhether the toggle button is selected by default (uncontrolled).
onChange(isSelected: boolean) => void-Handler that is called when the selection state changes.
isDisabledbooleanfalseWhether the toggle button is disabled.
aria-labelstring-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>