Toggle

Toggle represents one independent button state that remains pressed or not pressed.

Overview and decision boundary

Use Toggle for one independent button state that remains pressed or not pressed, such as following, pinning, muting, or showing an optional layer.

Do not use Toggle for immediate settings, form selection, disclosure, grouped selection, or a momentary action.

import { Bell, Save } from "@nerio-ui/adapters/icons";import { Toggle } from "@nerio-ui/ui/client";<Toggle icon={Bell} aria-label="Follow updates" defaultPressed /><Toggle icon={Save} aria-label="Save article for later" variant="outline" />

Installation and imports

Install the editable registry source, or use the matching package entrypoint when the product keeps Nerio as a workspace dependency.

pnpm exec nerio add toggleimport * as React from 'react';import { Check, Save } from '@nerio-ui/adapters/icons';import { Toggle } from '@nerio-ui/ui/client';

Usage

"use client";import * as React from 'react';import { Check, Save } from '@nerio-ui/adapters/icons';import { Toggle } from '@nerio-ui/ui/client';export function SaveToggle() {  const [saved, setSaved] = React.useState(false);  return (    <Toggle leadingIcon={saved ? Check : Save} pressed={saved} onPressedChange={setSaved}>      Save article    </Toggle>  );}

Variants

VariantUse
ghostRestrained default for dense or repeated controls.
outlineAdds a stable boundary around the independent state.
sm / md / lgShared action heights for icon-only and visible-label content.

Anatomy

SlotPurpose
toggleNative Base UI toggle button and public pressed-state owner.
toggle-iconOptional leading Nerio icon for visible-label content.
toggle-labelVisible label that remains semantically stable while state changes.

States

StateBehavior
Unpressedaria-pressed="false"; data-pressed is absent.
Pressedaria-pressed="true"; data-pressed adds a secondary fill and primary foreground while preserving the variant border.
Hover / activeTransient interaction remains distinct from the retained pressed state.
Focus-visibleShared focus ring remains visible in both pressed states.
DisabledActivation is blocked while pressed or unpressed presentation remains visible.

Motion

  • Hover and press reuse shared CSS-first interaction motion.
  • The retained pressed state never depends on animation.
  • Reduced motion removes nonessential duration and scale.

Accessibility

  • Uses the Base UI Toggle primitive and renders a native type=button by default.
  • Expose the persistent state through pressed, defaultPressed, onPressedChange, aria-pressed, and data-pressed.
  • Use a stable accessible name while the pressed state changes; do not alternate labels such as Mute and Unmute when aria-pressed is present.
  • Icon-only usage requires aria-label at the TypeScript level; visible-label usage derives its name from children unless an explicit ARIA name is supplied.
  • Enter, Space, pointer, and touch activation toggle exactly one state while focus remains on the control.
  • Disabled Toggle prevents state changes and preserves a visible pressed or unpressed state.
  • Use Toggle for an independent retained button state, Button for momentary actions, Switch for immediate settings, and Checkbox for selection.
  • ButtonGroup does not add grouped selection; use a future ToggleGroup for exclusive or multiple grouped values.
  • Pressed state uses a secondary surface with primary foreground while preserving the variant border; forced-colors mode adds a system highlight boundary, and the state does not depend on motion.

Review the shared responsibility and evidence boundaries in the Accessibility foundation alongside this component-specific contract. Use the Spacing & layout foundation for shared density, wrapping, overflow, reflow, and component-versus-product ownership guidance. The Color foundation, Typography foundation, and Localization foundation define the shared visual-role, text-resilience, direction, and locale boundaries used by component examples.

API

PropPurpose
pressed / defaultPressed / onPressedChangeControlled and uncontrolled state with Nerio event details and cancellation.
icon / aria-labelIcon-only mode with a required stable accessible name.
children / leadingIconVisible-label mode with an optional leading Nerio icon.
variantSelects "ghost" or "outline"; ghost is the default.
sizeSelects "sm", "md", or "lg"; md is the default.
valueStable identifier reserved for future direct ToggleGroup composition.
disabled / className / style / render / nativeButtonPreserves Nerio disabled and render-composition contracts.

Implementation contract

ContractValue
Registry itemtoggle installs 9 Tailwind-first source, utility, bridge, and token files.
Base UItoggle
Registry dependenciesNone.
Package dependencies@base-ui/react, @nerio-ui/adapters, clsx, react, tailwind-merge, tailwindcss

Styling contract

ContractValue
AuthoringComplete, statically detectable Tailwind CSS v4 recipes own component visuals.
ValuesSemantic and component --n-* variables remain the canonical customization layer.
OverridesCustomizable slots merge consumer className values with tailwindCn so conflicting utilities resolve deterministically.
Residual CSSOnly shared keyframes and scoped no-Preflight compatibility rules remain; there is no parallel visual selector layer.

Design notes

  • Persistent public state is pressed; active remains the transient pointer or keyboard state.
  • Button performs momentary actions, Switch changes settings, and Checkbox represents selection.
  • ButtonGroup owns layout only; grouped values and roving focus require ToggleGroup.

Do / do not

Do
Keep one stable label while aria-pressed communicates state. The visual icon may change to reinforce the selected state.
Do not
Use Toggle for immediate settings, form selection, disclosure, momentary actions, or grouped values.

Tokens

GroupTokensControls
Sizing--n-toggle-height-sm / --n-toggle-height-md / --n-toggle-height-lg / --n-toggle-radiusShared action geometry and density.
Unpressed--n-toggle-background-ghost / --n-toggle-background-outline / --n-toggle-border-outlineVariant-specific neutral surfaces.
Pressed--n-toggle-background-pressed / --n-toggle-border-pressed / --n-toggle-foreground-pressedSecondary retained-state fill with primary foreground and a neutral border.
Focus--n-focus-ringVisible keyboard focus in either pressed state.