react-switch

A draggable, accessible toggle-switch component for React with mouse, touch, and keyboard support out of the box.

Library
npm
v7.1.0
1,339stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
38/100Needs Attention
Development Activity0
Maintenance0
Community52
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
63/100Good
Architecture60
Code Quality62
Innovation75
Learning Curve55

react-switch renders a single customizable toggle-switch component that can be dragged with the mouse or a touch screen, clicked, or operated via keyboard, and wires up the correct accessibility semantics (role=“switch”, aria-checked, focus outline) automatically. It ships as a controlled component: the consumer owns the checked state and passes an onChange handler, keeping the library’s internal footprint small (under 2.5kB gzipped) since it uses inline styles instead of a stylesheet.

Beyond the default look, colors (on/off track and handle), icons, dimensions, border radius, and box-shadow are all configurable via props, and any unrecognized props are forwarded to the underlying checkbox input so consumers can add native HTML attributes like name or required without extra wrapper code.

What You Get

  • A controlled Switch component driven entirely by checked and onChange props, so it fits cleanly into any existing form state management
  • Built-in drag support for both mouse and touch, with a halfway-checkpoint rule that toggles state if the handle is dragged more than 50% of the way across
  • Correct accessibility wiring out of the box: role=“switch”, aria-checked, a hidden native checkbox input, and a visible focus outline that only appears on keyboard focus
  • Full visual customization via props: track colors, handle colors, custom checked/unchecked icons, handle diameter, height, width, and border radius
  • A tiny runtime footprint (under 2.5kB gzipped) achieved by using inline styles rather than a bundled CSS file

Common Use Cases

  • Settings screens that need an on/off toggle for boolean preferences (notifications, dark mode, feature flags)
  • Forms where a checkbox needs to look and feel like an iOS/Material-style switch rather than a square checkbox
  • Dashboards and admin panels toggling a resource’s enabled/disabled state inline in a table row
  • Any React app wanting drag-to-toggle interaction (not just click) for a more tactile mobile experience

Under The Hood

Architecture The library is a single stateful class component (src/index.jsx) that owns all drag/click/keyboard/focus logic, delegating only pure, side-effect-free calculations to two extracted helper modules: getBackgroundColor.js (interpolates track/handle color between off and on states based on drag position) and hexColorPropType.js (a custom PropTypes validator restricting color props to hex strings). Mouse and touch input converge on shared $onDragStart/$onDrag/$onDragStop methods, and the constructor precomputes $checkedPos/$uncheckedPos bounds from height, width, and handleDiameter that every subsequent position, opacity, and transform calculation in render() depends on — meaning any change to how those bounds are derived cascades through nearly the entire render method. There is no internal layering beyond this, which is appropriate given the component’s narrow, single-purpose surface area.

Tech Stack The only runtime dependency is prop-types (^15.7.2); react and react-dom are peer dependencies supporting a wide range (^15.3.0 through ^19.0.0). The build pipeline uses Rollup (with rollup-plugin-babel, rollup-plugin-buble, and rollup-plugin-terser) to produce separate dev and production bundles as both CJS and ESM, wired up through the package’s exports map, while Babel 7 (preset-env, preset-react) handles transpilation. A separate Webpack 5 config builds the demo site. Tests run on Jest 26 with @testing-library/react 16, and linting uses ESLint with the Airbnb config plus Prettier for formatting.

Code Quality Tests exist under __tests__/ covering the two pure helper functions directly (getBackgroundColor.test.js, hexColorPropType.test.js) plus component-level behavior (Switch.test.jsx) including snapshot tests for default and custom prop rendering, and behavioral assertions for focus/blur outline changes and drag-triggered state transitions. Error handling relies on PropTypes validation rather than thrown exceptions — including a hand-written hexColorPropType validator for color props — with no TypeScript compilation in the source, though a hand-authored index.d.ts ships for TypeScript consumers. Internal-only instance fields and state keys consistently use a $ prefix (e.g. $onMouseDown, $checkedPos) to visually separate them from public props, and a GitHub Actions workflow runs CI on changes.

API Design The public API needs only two required props (checked, onChange) to function, with every other prop — colors, icons, dimensions, box-shadow — defaulted sensibly, so getting a working switch on screen requires minimal boilerplate. Prop names are consistent and self-explanatory (offColor/onColor for the track, offHandleColor/onHandleColor for the handle, checkedIcon/uncheckedIcon vs checkedHandleIcon/uncheckedHandleIcon), and any extra props are spread onto the underlying input so consumers can pass native HTML attributes without a wrapper. Accessibility is handled by default (role=“switch”, aria-checked, focus outline logic) rather than requiring consumers to wire it up themselves, and the README documents label-association patterns for screen-reader users explicitly.

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