Shadcn Toggle
React toggle for two-state buttons for formatting controls and feature toggles. Built with TypeScript and Tailwind CSS for Next.js using Radix UI.
Toggle state issues?
Join our Discord community for help from other developers.
Ever clicked a bold button in an editor and wondered if it actually worked? You click, nothing visible happens, then you type and realize formatting isn't active. That's the frustration toggles solve—they stay pressed when active, so you always know what state you're in. This shadcn/ui toggle makes binary controls feel obvious and reliable in your React applications.
Basic toggle button
Simple bold formatting toggle:
Clean pressed/unpressed states with visual feedback. This free open source React component handles all the accessibility requirements and keyboard navigation for two-state controls. Built with TypeScript for full type safety while styled with Tailwind CSS to match your design system in Next.js applications.
npx shadcn@latest add toggle
Why toggles improve user experience
Here's the thing—regular buttons leave users guessing about state. Click a "Bold" button and nothing visible changes until you start typing. That's cognitive overhead. Toggles eliminate that uncertainty by showing exactly what's active right now.
Toggles solve real interface problems:
- State visibility - Users instantly see what's active without testing
- Persistent feedback - Button stays pressed while feature is on
- Less cognitive load - No guessing about current state in JavaScript applications
- Familiar pattern - Everyone knows how toggle buttons work from text editors
- Space efficient - One button handles both on and off states
- Immediate response - Visual feedback happens instantly on interaction
Common patterns you'll actually use
Text formatting group
Multiple toggles working together:
Rich text toolbar
Complete editor toolbar with grouped toggles:
Look, toggles shine in toolbars and formatting controls where users need instant visual feedback. Text formatting is the classic use case, but they work great for view modes, filter states, or any feature that's either on or off.
Built on Radix UI with full TypeScript support and Tailwind CSS styling. The accessibility stuff is handled for you—ARIA attributes, keyboard navigation, screen reader support.
API Reference
Toggle
A two-state button component.
Prop | Type | Default | Description |
---|---|---|---|
pressed | boolean | - | The controlled pressed state of the toggle |
defaultPressed | boolean | false | The default pressed state (uncontrolled) |
onPressedChange | (pressed: boolean) => void | - | Event handler called when the pressed state changes |
disabled | boolean | false | When true, prevents the user from interacting with the toggle |
variant | "default" | "outline" | "default" | The visual style variant |
size | "default" | "sm" | "lg" | "default" | The size of the toggle |
className | string | - | Additional CSS classes |
Data Attributes
The toggle automatically applies data attributes for styling:
Attribute | Values | Description |
---|---|---|
[data-state] | "on" | "off" | Indicates whether the toggle is pressed |
[data-disabled] | Present when disabled | Applied when the toggle is disabled |
Size Variants
Size | Description |
---|---|
sm | Smaller toggle for compact toolbars |
default | Standard size for most use cases |
lg | Larger toggle for primary actions |
Style Variants
Variant | Description |
---|---|
default | Filled style with solid background when pressed |
outline | Outlined style with border emphasis |
Keyboard Navigation
The toggle supports full keyboard interaction:
Key | Description |
---|---|
Space | Activates/deactivates the toggle |
Enter | Activates/deactivates the toggle |
Accessibility Features
Built-in accessibility support includes:
- ARIA attributes - Proper
aria-pressed
state communication - Keyboard support - Space and Enter keys toggle state
- Focus management - Clear focus indicators
- Screen reader support - State changes are announced
- Semantic button - Uses proper button semantics
- Label association - Connects with aria-label or external labels
Styling Examples
The toggle component supports different variants and sizes. Check the preview examples above to see various styling options in action, including outline variants, different sizes, and text labels.
Common use cases
Toggles work great for these scenarios:
- Text formatting - Bold, italic, underline controls
- View modes - List vs grid, expanded vs collapsed
- Filter states - Show/hide categories, active filters
- Feature flags - Enable/disable functionality
- Layout options - Sidebar visibility, panel states
- Tool selection - Active drawing tools, editing modes
- Status indicators - Favorite, bookmark, follow states
Things to watch out for
Make pressed states obvious. The default styling is good, but double-check your design system. Users shouldn't have to guess whether a toggle is active—especially in light/dark mode switches.
Group related toggles logically. Bold/italic/underline together, alignment controls together. Don't scatter related functionality across your toolbar.
Handle async operations properly. If your toggle triggers a server request, disable it during the operation and handle failures gracefully. Nothing worse than a toggle that appears to work but silently fails.
Test with keyboard navigation. Tab order should make sense, and Space/Enter should work consistently across all your toggles.
Works well with
Toggles fit naturally in Button toolbars—mix regular buttons with toggles for actions vs state controls.
Wrap toggle groups in Card components for settings panels. Use Separator to visually group related toggles in complex toolbars.
Badge components are useful for showing counts when toggles filter content. Tooltip helps with icon-only toggles.
For text editors, combine with Textarea for the actual content area, or Input for inline editing modes.
Quick guidelines
- Use aria-label or visible text for clarity
- Make pressed states visually obvious
- Group related toggles together
- Keep consistent sizing within groups
- Choose clear icons that represent the action
- Persist state appropriately (session vs permanent)
- Show loading during async operations
- Revert state on errors