Components
- Accordion
- Alert
- Alert Dialog
- Aspect Ratio
- Attachment
- Avatar
- Badge
- Breadcrumb
- Bubble
- Button
- Button Group
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Collapsible
- Combobox
- Command
- Context Menu
- Date Picker
- Dialog
- Drawer
- Dropdown Menu
- Empty
- Field
- Hover Card
- Input
- Input OTP
- Input Group
- Item
- Kbd
- Label
- Marker
- Menubar
- Message
- Message Scroller
- Native Select
- Navigation Menu
- Pagination
- Popover
- Progress
- Radio Group
- Resizable
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toggle
- Toggle Group
- Tooltip
- New Component
Elements
Charts
Icons
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
| Prop | Type | Default | Description |
|---|---|---|---|
pressed | boolean | — | Controlled pressed state |
defaultPressed | boolean | false | Uncontrolled 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 |
disabled | boolean | false | Disables 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 minimumInstallation
$ npx shadcn add \https://gin-design.vercel.app/toggle