
City bike, Trek FX 2
New York · today, 2:20 PM
$320
Buttons & Actions
Toggle
v1.0.0Added 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.
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 toggleToggle 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
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>
)
}childrendefault "Delivery only"ReactNodeThe 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 ""stringAny 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 falsebooleanStarting state while uncontrolled.
pressedbooleanControlled state. Pair it with onPressedChange; without a handler the toggle stays where you put it.
onPressedChange(pressed: boolean) => voidCalled with the next state on click, Space, Enter or the shortcut.
disableddefault falsebooleanDims the toggle, blocks clicks and the shortcut, and keeps its current state.
fullWidthdefault falsebooleanStretches to the container width, e.g. a Follow toggle at the bottom of a phone screen.
shortcutdefault ""stringA 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 falsebooleanRenders 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.
leftIconReactNodeAn icon before the label. Unsized svgs follow the size (14 / 16 / 18px).
pressedIconReactNodeReplaces 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.
classNamesPartial<Record<"icon" | "label", string>>Extra classes for the inner parts: the icon wrapper and the label wrapper.
classNamestringExtra classes for the toggle itself, merged last. Style the pressed state with data-[state=on]:, e.g. data-[state=on]:bg-background/90.
Icon toggles in a toolbar. Focus the text and ⌘B, ⌘I, ⌘U and ⇧⌘X flip them through the shortcut prop.
ghost and outline take the selected tint when pressed; soft turns into the solid fill.
The tone only colors the pressed state: a solid fill on soft, a tint and border on outline.
32, 40 and 48px plus square icon sizes; 44px on touch screens.
radius full with a check as pressedIcon: the pill springs open to make room and its neighbors glide along.
Bell turns into BellOff. The aria-label names what pressed means (Mute notifications) and stays the same; aria-pressed carries the state.
Any CSS color for the pressed fill, fullWidth for the bottom of a phone screen.
The preview, props and docs are free; copying the source needs a Pro plan. See plans.
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.
On a phone the medium size is 44px tall and the small one keeps a 44px hit area.

New York · today, 2:20 PM
$320
783 listingsTap the filters and the heart