For the complete documentation index, see llms.txt. Markdown variants are available by appending .md to any URL or sending an Accept: text/markdown header. An agent skill is available at /.well-known/agent-skills/site-skill.md.
Home

Toggle

A two-state button that can be pressed on or off, with sound feedback and multiple visual variants.

Microphone is active
import { BoldIcon, ItalicIcon, MicIcon, MicOffIcon, StarIcon, UnderlineIcon } from "lucide-react";
import { useState } from "react";
import { Toggle } from "@/components/ui/toggle";

export const ToggleDemo = () => {
  const [muted, setMuted] = useState(false);

  return (
    <div className="flex flex-col gap-6">
      {/* Default — text */}
      <div className="flex flex-wrap gap-2">
        <Toggle>Bold</Toggle>
        <Toggle defaultPressed>Pressed</Toggle>
        <Toggle disabled>Disabled</Toggle>
      </div>
      {/* With icon */}
      <div className="flex flex-wrap gap-2">
        <Toggle aria-label="Bold"><BoldIcon /></Toggle>
        <Toggle aria-label="Italic" defaultPressed><ItalicIcon /></Toggle>
        <Toggle aria-label="Underline"><UnderlineIcon /></Toggle>
      </div>
      {/* Outline variant */}
      <div className="flex flex-wrap gap-2">
        <Toggle variant="outline" aria-label="Bold">
          <BoldIcon />
          Bold
        </Toggle>
        <Toggle variant="outline" aria-label="Italic" defaultPressed>
          <ItalicIcon />
          Italic
        </Toggle>
        <Toggle variant="outline" aria-label="Underline">
          <UnderlineIcon />
          Underline
        </Toggle>
      </div>
      {/* Sizes */}
      <div className="flex flex-wrap items-center gap-2">
        <Toggle size="sm" aria-label="Favourite"><StarIcon /></Toggle>
        <Toggle size="default" aria-label="Favourite"><StarIcon /></Toggle>
        <Toggle size="lg" aria-label="Favourite"><StarIcon /></Toggle>
      </div>
      {/* Controlled — mute toggle */}
      <div className="flex items-center gap-3">
        <Toggle
          pressed={muted}
          onPressedChange={setMuted}
          variant="outline"
          aria-label={muted ? "Unmute" : "Mute"}
        >
          {muted ? <MicOffIcon /> : <MicIcon />}
          {muted ? "Unmuted" : "Mute"}
        </Toggle>
        <span className="text-muted-foreground text-sm">Microphone is {muted ? "muted" : "active"}</span>
      </div>
    </div>
  );
};

Variants

<Toggle>Default</Toggle>
<Toggle variant="outline">Outline</Toggle>
<Toggle variant="ghost">Ghost</Toggle>
<Toggle variant="secondary">Secondary</Toggle>

Sizes

<Toggle size="sm"><BoldIcon /></Toggle>
<Toggle size="default"><BoldIcon /></Toggle>
<Toggle size="lg"><BoldIcon /></Toggle>
<Toggle size="icon"><BoldIcon /></Toggle>

With icon and label

<Toggle variant="outline">
  <BoldIcon />
  Bold
</Toggle>

Controlled

const [pressed, setPressed] = useState(false);
 
<Toggle pressed={pressed} onPressedChange={setPressed}>
  {pressed ? "On" : "Off"}
</Toggle>

Sound

Toggle always plays toggleOn when pressed and toggleOff when released — no extra prop required.

Props

PropTypeDefaultDescription
pressedboolean—Controlled pressed state
defaultPressedbooleanfalseUncontrolled initial state
onPressedChange(pressed: boolean) => void—Callback on state change
variant"default" | "outline" | "ghost" | "secondary""default"Visual style
size"sm" | "default" | "lg" | "icon" | "icon-sm""default"Button size
disabledbooleanfalseDisables interaction

Usage

import { Toggle } from "@/components/ui/toggle";
 
<Toggle defaultPressed aria-label="Bold">
  <BoldIcon />
</Toggle>

Specs

# Mint — Toggle Specs
 
## Component
- name: toggle
- file: registry/mint/toggle.tsx
- installs to: components/ui/toggle.tsx
- dependencies: radix-ui, class-variance-authority
- registryDependencies: none
 
## What is it
A two-state button built on Radix Toggle.Root that can be pressed on or off.
Use it for formatting controls, filters, or any binary option that benefits
from a persistent pressed state. Prefer Toggle over a checkbox when the
action is immediate and visual feedback matters more than form semantics.
 
## Visual identity
Transparent base with accent-coloured pressed state keeps the toggle
unobtrusive until activated. Standard border radius (rounded-md) and
medium font weight match Mint's density and character.
 
## Design tokens
--muted: oklch(0.96 0.02 155) / oklch(0.2 0.03 155)              — hover background (default variant)
--muted-foreground: oklch(0.52 0.06 155) / oklch(0.6 0.06 155)   — hover text colour
--accent: oklch(0.92 0.05 155) / oklch(0.26 0.05 155)              — pressed background
--accent-foreground: oklch(0.32 0.1 155) / oklch(0.88 0.06 155)  — pressed text
--secondary: oklch(0.95 0.04 155) / oklch(0.22 0.04 155)           — secondary variant background
--secondary-foreground: oklch(0.32 0.1 155) / oklch(0.88 0.06 155)
--input: oklch(0.88 0.04 155 / 60%) / oklch(0.32 0.05 155 / 40%)            — outline variant border
--ring: oklch(0.5 0.14 155) / oklch(0.62 0.15 155)               — focus ring
--destructive: oklch(0.55 0.25 15) / oklch(0.704 0.191 22.216) — aria-invalid ring
 
## Variants
- default    → transparent base, accent fill when pressed. General-purpose toolbar or standalone toggle.
- outline    → grey border, transparent fill. Use when the toggle must be visually distinct at rest.
- ghost      → no border, no fill; softer accent/80 when pressed. Low-emphasis toggle in dense UIs.
- secondary  → secondary background at rest, dimmed when pressed. Use for filters or chip-style toggles.
 
## Sizes
- sm       → h-8 min-w-8 px-1.5. Compact toolbars or inline controls.
- default  → h-9 min-w-9 px-2. Standard size; use unless space is constrained.
- lg       → h-10 min-w-10 px-2.5. Prominent or touch-friendly targets.
- icon     → size-9. Square icon-only toggle at default height.
- icon-sm  → size-8. Square icon-only toggle at sm height.
 
## States
- hover:        bg-muted + text-muted-foreground (all variants); ghost uses bg-accent (light) / bg-accent/50 (dark)
- data-[state=on]: bg-accent + text-accent-foreground (default/ghost); bg-secondary/60 (secondary)
- focus-visible: border-ring + ring-[3px] ring-ring/50
- disabled:     opacity-50, pointer-events-none
- aria-invalid:  border-destructive + ring-destructive/20 (ring-destructive/40 dark)
 
## Conventions
- sounds: GIN Design exclusive — always plays toggleOn when pressed and toggleOff when released via useFeedback; no prop required
- Sub-components expose data-slot="toggle" for CSS targeting
- Icon-only toggles require aria-label
- SVG icons auto-size to 16px — do not override unless intentional
- toggleVariants is exported for use by ToggleGroup
- gap-2 spacing between adjacent toggles minimum

Installation

GIN Design Plugin
$ npx shadcn add https://gin-design.vercel.app/toggle