rc-switch

Accessible React switch component with controlled and uncontrolled toggle modes.

Library
npm
v4.1.0
196stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
61/100Good
Development Activity48
Maintenance40
Community76
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
73/100Good
Architecture65
Code Quality78
Innovation85
Learning Curve65

rc-switch is a small, focused React component that renders a boolean on/off toggle as a native, accessible button. It’s one of the foundational rc-component packages that power Ant Design’s form controls, exposing a Switch that works equally well as a fully controlled component (checked/onChange) or an uncontrolled one (defaultChecked), with keyboard support (left/right arrow toggling) and slots for custom checked/unchecked labels built in from the start.

Because it renders a real <button role="switch" aria-checked> rather than a styled checkbox, accessibility semantics come for free — screen readers and keyboard navigation work without any extra ARIA wiring from the consumer. The component ships as plain class-name driven markup (no CSS-in-JS), so teams can restyle it entirely via the prefixCls prop and an accompanying stylesheet, which is exactly how design systems like Ant Design layer their own visual treatment on top of it.

What You Get

  • A <Switch /> component rendering a native, focusable button with correct role="switch" and aria-checked semantics
  • Controlled (checked/onChange) and uncontrolled (defaultChecked) usage modes via a shared internal state hook
  • Built-in keyboard support — left arrow switches off, right arrow switches on, in addition to click/space toggling
  • Slots for custom checked/unchecked content (checkedChildren/unCheckedChildren) plus a loadingIcon slot for async toggle states
  • Class-name driven styling via prefixCls, className, and semantic classNames/styles content overrides — no CSS-in-JS lock-in
  • A disabled state that suppresses both click and keyboard toggling while still rendering the current value

Common Use Cases

  • Settings and preference toggles (dark mode, notifications, feature flags) in a dashboard or admin UI
  • Building a themed Switch primitive for a component library or design system on top of the unstyled base behavior
  • Boolean fields inside forms where a checkbox isn’t the desired visual pattern
  • Toggle controls inside data tables or list rows (e.g. enable/disable a row’s status) that need accessible keyboard interaction

Under The Hood

Architecture The entire package is a single component module (src/index.tsx, ~127 lines): a forwardRef function component that derives its checked state through @rc-component/util’s useControlledState hook, funnels every click and keydown event through one internal triggerChange function, and composes its class name with clsx. There is no internal layering beyond this — no separate hooks directory, no context, no sub-components — which keeps the surface area intentionally minimal; the only place complexity could grow is if more interaction modes were added to triggerChange and onInternalKeyDown.

Tech Stack Written in TypeScript and built with father (the rc-component ecosystem’s shared build tool) into both CommonJS (lib) and ESM (es) outputs, with a separate Less-to-CSS compile step (assets/index.lessassets/index.css) for the stylesheet. Runtime dependencies are limited to @rc-component/util (shared hooks/keycode constants across the rc-component family) and clsx for conditional class names, with react/react-dom as peer dependencies. The docs/demo site is built with dumi, linting runs through a flat ESLint config combining typescript-eslint with the React and Jest plugins, and Prettier plus a Husky pre-commit hook enforce formatting on every commit. CI runs via a GitHub Actions workflow with Codecov coverage reporting, and releases are cut through the shared @rc-component/np tool.

Code Quality A single Jest test suite (via rc-test, the rc-component test runner, and @testing-library/react) exercises the behaviors that matter most for a toggle: click-to-toggle, left/right arrow keyboard toggling, controlled-to-uncontrolled transitions, and the exact arguments passed to onChange/onClick. Typing is precise — dedicated SwitchChangeEventHandler/SwitchClickEventHandler types and a narrow prop interface that omits the native onChange/onClick it replaces. There’s no async or I/O path, so error handling is limited to guarding the disabled state inside triggerChange, which is handled explicitly and consistently.

API Design The public surface is small and conventionally named: checked/defaultChecked mirror React’s own controlled/uncontrolled component pattern, checkedChildren/unCheckedChildren give label slots without requiring children composition, and the newer styles/classNames sub-object props follow the rc-component convention for granular style overrides without needing to override the whole component’s CSS. Zero props are required — <Switch /> alone renders a working toggle — and forwardRef gives consumers direct access to the underlying button element when needed.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search