Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelogContact
Components
Buttons & Actions
ButtonButton GroupCopy ButtonDelete ButtonTheme ToggleToggleToggle Group
Inputs
Avatar UploadCalendarCheckboxColor PickerComboboxCountry SelectCron PickerCurrency InputDate PickerDate Range PickerDate Time PickerDuration PickerEmail InputEmoji PickerFile UploadFilter BuilderInputInput GroupListboxMasked InputMention InputMonth PickerMulti SelectNumber InputOTP InputPassword InputPhone InputRadio GroupRatingSearch InputSegmented ControlSelectSignature PadSliderSwitchTag InputTextareaTime PickerTimezone SelectTree Select
Forms
Address InputBooking WidgetCSV ImportFieldForm WizardInline EditInvoice line itemsRich Text EditorSchema Builder
Navigation
Back To TopBounce SidebarBreadcrumbCommand MenuGlobal SearchGooey NavHook SidebarNav MenuNav TabsPaginationProximity SidebarScroll ProgressSidebarStepsTable Of ContentsTabsTopbarUser MenuWorkspace Switcher
Overlays
Alert DialogContext MenuDialogDrawerDropdown MenuFamily DrawerHover CardPopoverShare DialogSheetShortcuts DialogTooltipTour
Feedback
AlertBannerCookie ConsentEmoji ReactionEmpty StateNotification BellNotification CenterProgressRoute ProgressSetup ChecklistSkeletonSpinnerToast
Data Display
Approval FlowAvatarBadgeCalendar ViewCode BlockComment ThreadContact cardCountdownDescription ListDiff ViewerFile ListFile managerFolderGanttJSON ViewerKbdLog ViewerMarkdownPresenceSchedulerTagTimelineTree View
Tables & Lists
Audit LogData TableDeal PipelineEditable GridKanbanListMembers tablePermissions MatrixTableTask ListVirtual List
Charts & Stats
Animated CounterArea chartBar chartDonut chartFunnel chartGaugeGitHub ActivityHeatmap calendarLeaderboardLine chartRadar chartRadial barSparklineStat CardTrackerTrend badge
Layout
AccordionApp ShellCardCollapsibleDetail LayoutEntity HeaderPage HeaderScroll AreaSeparatorSettings LayoutSplit ViewToolbar
Media
Audio PlayerCarouselCSV ViewerDOCX EditorDOCX ViewerExcel ViewerFile SystemImage compareImage CropperImage GalleryImage LightboxLocation MapPDF ViewerPowerPoint ViewerQR CodeStep PlayerVideo Player
AI Kit
Agent Status CardChat MessageChat ThreadChat WidgetConversation ListFluid OrbGrid RevealMatrix OrbModel PickerPrompt InputReasoning IndicatorRule BuilderSuggestion ChipsTool Call TimelineUsage MeterVoice InputWorkflow Canvas
Text & Effects
Background PatternGravity LettersMarqueeTerminalText AnimateText Rotate
Mobile
Action SheetBottom Tab BarFABHaptic ButtonHero HeaderInstall PromptLarge Title HeaderNotification BannerOnboarding CarouselPicker WheelPull To RefreshSlide To ConfirmSticky CTA BarSwipe DeckSwipeable Tabs
Commerce
Cart drawerCategory pickerCheckout stepsCoupon inputFavorite buttonFilter panelListing cardListing gridOrder trackerPricePrice rangePricing tableProduct galleryQuantity stepperReviewsSeller card
Marketing Sections
App Download SectionBlog Cards SectionCTA SectionFAQ SectionFeature GridFeature ShowcaseHero SectionIntegrations SectionLogo CloudMarketing FooterMarketing HeaderMarketing SectionNewsletter SectionPricing SectionStats SectionSteps SectionTeam SectionTestimonials SectionTimeline SectionVideo Section
Blocks
Admin Dashboard PageAdmin ShellAI Chat PageAPI Keys PageAutomation Builder PageCheckout PageCRM Contact PageCRM Pipeline PageError PagesInbox PageInvoice PageKPI DashboardListing Detail PageLogin PageMarketplace Home PageMarketplace Search PageMarketplace ShellMobile App HomeOnboarding FlowOrder History PagePost Listing WizardPricing PageProfile PageRegister PageSettings PageUsers Admin Page
Templates
About PageAcademy PageAccessibility PageAffiliate PageAgency PageAI Product PageAppointment Booking PageBlog PageBlog Post PageBug Bounty PageCareers PageChangelog PageCommunity PageCompare PageContact PageCustomer Story PageCustomers PageDemo Booking PageDevelopers PageDocs Home PageDownload PageEnterprise PageEvents PageExperts PageFAQ PageFeature PageGlossary PageHelp Article PageHelp Center PageHome Services PageImpact PageIntegration Detail PageIntegrations PageJob Detail PageLanding PageLaunch PageLegal PageManifesto PagePortfolio PagePress PageProduct Tour PagePromo PageReal Estate PageReferral PageResearch Report PageRestaurant PageRoadmap PageROI Calculator PageSecurity PageSolutions PageStartups PageStatus PageStorefront PageSwitch PageTemplate Gallery PageTravel PageWaitlist PageYear in Review Page
Hooks & Utilities
AI ChatChart kitCommerceDate utilsFile exportFile typesFiltersForm validationHapticsInvoicingMotion presetsNavigationNumber formatRelative timeRomanian locationsSpreadsheetText matchTonesUIProvideruseClipboarduseConsentuseControllableStateuseCooldownuseDebounceuseKeyboardInsetuseLocaleuseLongPressuseMediaControlsuseMediaQueryuseOverflowItemsusePersistedStateuseScrollEdgesuseScrollStateuseSelectionuseShortcutuseStickToBottom
GalleryTheme

Buttons & Actions

Toggle

Buttons & Actions

Toggle React component for Tailwind CSS v4

Theme ToggleToggle Group
Live props
Content
children
Appearance
variant
tone
color
size
radius
State
defaultPressed
disabled
Layout
fullWidth
Behavior
shortcut
asChild
Code
import { Toggle } from "@/components/ui/toggle"

<Toggle>Delivery only</Toggle>
  1. Home
  2. Components
  3. Buttons & Actions
  4. Toggle
Pro

Toggle React component for Tailwind CSS v4

v1.0.0·Added in 1.0.0

A React toggle button that stays pressed, for bold and italic in an editor, a favorite heart, mute, or a filter pill.

Click or tap it and it stays pressed: the surface takes the selected tint (soft turns into a solid fill) and it dips on a quick spring while your finger is down. Click again to release it. With a mouse it tints on hover, deeper when it is already pressed. Tab to it and press Space or Enter; screen readers hear the state through aria-pressed while the label stays the same. With pressedIcon the icon pops into its pressed form (an outline heart turns into a filled one, a bell into a muted bell), and a filter pill grows a check mark. A shortcut such as mod+b flips it from anywhere on the page. On a phone the medium size is 44px tall and the small one keeps a 44px hit area.

Toggle is a Pro React component in the React button components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add toggle, together with Motion presets, Tones, useControllableState, useShortcut and UIProvider and the npm packages @radix-ui/react-toggle, @radix-ui/react-slot and motion.

Add to a project

Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup

npx wingo-ui@latest add toggle

Toggle is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans

Usage

Import Toggle from @/components/ui/toggle.

import { Check, Heart } from "lucide-react"
import { Toggle } from "@/components/ui/toggle"

export function ListingActions({ saved, onSavedChange }: { saved: boolean; onSavedChange: (saved: boolean) => void }) {
  return (
    <div className="flex items-center gap-2">
      <Toggle variant="outline" radius="full" pressedIcon={<Check />}>
        Delivery only
      </Toggle>
      <Toggle
        size="icon"
        radius="full"
        tone="danger"
        pressed={saved}
        onPressedChange={onSavedChange}
        pressedIcon={<Heart className="fill-current" />}
        aria-label="Save to favorites"
      >
        <Heart />
      </Toggle>
    </div>
  )
}

Props

  • childrendefault "Delivery only"
    ReactNode

    The label. For icon sizes pass the icon itself plus an aria-label, and keep the label the same in both states and name what pressed means (Bold, Mute notifications): aria-pressed already says whether it is on.

  • variantdefault "ghost"
    "ghost" | "outline" | "soft"

    ghost is transparent with muted text and takes the selected tint when pressed (toolbars). outline adds a hairline border that turns to the tone when pressed (filter chips). soft rests on a light fill and becomes the solid tone fill when pressed, so the on state is loud.

  • tonedefault "neutral"
    "neutral" | "brand" | "success" | "warning" | "danger" | "info"

    Color of the pressed state. neutral is the gray selected tint (black or white fill on soft); the other tones tint the pressed state and color its text.

  • colordefault ""
    string

    Any CSS color for the pressed state. Replaces the tone; on soft the text on the fill turns black or white by lightness. Leave empty to use the tone.

  • sizedefault "md"
    "sm" | "md" | "lg" | "icon-sm" | "icon" | "icon-lg"

    The button's size table: 32 / 40 / 48px tall with matching padding, type and icon size. The icon sizes are square and need an aria-label. On touch screens md grows to 44px and sm keeps its look with a 44px hit area.

  • radiusdefault "md"
    "none" | "sm" | "md" | "lg" | "full"

    Corner shape, scaled with the size (md is 8 / 10 / 12px). full makes a pill, the usual look for filters.

  • defaultPresseddefault false
    boolean

    Starting state while uncontrolled.

  • pressed
    boolean

    Controlled state. Pair it with onPressedChange; without a handler the toggle stays where you put it.

  • onPressedChange
    (pressed: boolean) => void

    Called with the next state on click, Space, Enter or the shortcut.

  • disableddefault false
    boolean

    Dims the toggle, blocks clicks and the shortcut, and keeps its current state.

  • fullWidthdefault false
    boolean

    Stretches to the container width, e.g. a Follow toggle at the bottom of a phone screen.

  • shortcutdefault ""
    string

    A key combo in mod+k notation ("mod+b", "shift+mod+x"; mod is ⌘ on Apple devices and Ctrl elsewhere) that flips the toggle from anywhere on the page. Also sets aria-keyshortcuts. Bare keys are ignored while typing. Pass it only while the toggle should listen, e.g. while its editor has focus.

  • asChilddefault false
    boolean

    Renders your single child (a router link for URL filters, your own button) with the toggle's look, state, press and icons. A child that is not a button gets role="button" and flips on Space too, so aria-pressed is announced. The demo turns the first filter into an <a>. As in Radix, calling event.preventDefault() in your onClick cancels the flip.

  • leftIcon
    ReactNode

    An icon before the label. Unsized svgs follow the size (14 / 16 / 18px).

  • pressedIcon
    ReactNode

    Replaces leftIcon (or the icon child in icon sizes) while pressed, popping in on a spring: an outline heart to a filled one, Bell to BellOff. On a text toggle without leftIcon it only shows while pressed and the width springs open, like a filter chip growing a check, with the neighbors gliding along.

  • classNames
    Partial<Record<"icon" | "label", string>>

    Extra classes for the inner parts: the icon wrapper and the label wrapper.

  • className
    string

    Extra classes for the toggle itself, merged last. Style the pressed state with data-[state=on]:, e.g. data-[state=on]:bg-background/90.

Examples

Editor formatting

Icon toggles in a toolbar. Focus the text and ⌘B, ⌘I, ⌘U and ⇧⌘X flip them through the shortcut prop.

Variants and states

ghost and outline take the selected tint when pressed; soft turns into the solid fill.

Tones

The tone only colors the pressed state: a solid fill on soft, a tint and border on outline.

Sizes

32, 40 and 48px plus square icon sizes; 44px on touch screens.

Filter pills

radius full with a check as pressedIcon: the pill springs open to make room and its neighbors glide along.

Mute notifications

Bell turns into BellOff. The aria-label names what pressed means (Mute notifications) and stays the same; aria-pressed carries the state.

Custom color, full width

Any CSS color for the pressed fill, fullWidth for the bottom of a phone screen.

Dependencies

@radix-ui/react-toggle@radix-ui/react-slotmotionmotiontonesuse-controllable-stateuse-shortcutui-config

Files

  • components/ui/toggle.tsx

FAQ

Is the React Toggle component free?

The preview, props and docs are free; copying the source needs a Pro plan. See plans.

How do I install Toggle?

Run npx wingo-ui@latest add toggle. It also adds the Wingo UI items it builds on (Motion presets, Tones, useControllableState, useShortcut and UIProvider) and the npm packages @radix-ui/react-toggle, @radix-ui/react-slot and motion. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/toggle.

How does Toggle behave on phones?

On a phone the medium size is 44px tall and the small one keeps a 44px hit area.

See also

Toggle GroupButtonFavorite buttonToneslibuseShortcuthook

Used in

Rich Text EditorLog ViewerToolbarPrompt Input

More React button components

Button GroupCopy ButtonTheme ToggleDelete Button
All 7 React button components
PreviousTheme ToggleNext Toggle Group
Trek FX 2 city bike, parked on a street

City bike, Trek FX 2

New York · today, 2:20 PM

$320

783 listings·Tap the filters and the heart