# Click Wheel

> An unstyled rotary input for React with pointer, scroll and keyboard controls, haptics and optional inertia.

## Install

```bash
pnpm add click-wheel
```

Requires React 19.2 or newer. Import `{ ClickWheel }` from `"click-wheel"`.

## Optional themes

Add a theme to a project configured for shadcn. Each theme depends on the npm package.

- `pnpm dlx shadcn@latest add https://click-wheel.jackymo.me/r/click-wheel-shadcn.json`
- `pnpm dlx shadcn@latest add https://click-wheel.jackymo.me/r/click-wheel-ipod.json`
- `pnpm dlx shadcn@latest add https://click-wheel.jackymo.me/r/click-wheel-retro.json`
- `pnpm dlx shadcn@latest add https://click-wheel.jackymo.me/r/click-wheel-galley.json`

## Docs

- [All docs as one Markdown file](https://click-wheel.jackymo.me/docs.md)
- [Getting Started](https://click-wheel.jackymo.me/docs): An unstyled rotary input for React.
- [Styling](https://click-wheel.jackymo.me/docs/styling): Style the parts with data attributes, CSS variables or functions of state..
- [API Reference](https://click-wheel.jackymo.me/docs/api)
- [Default](https://click-wheel.jackymo.me/examples/default): Examples of styling, gearing, detents, inertia and controlled state..
- [Themes](https://click-wheel.jackymo.me/examples/themes)
- [Everything in one file](https://click-wheel.jackymo.me/llms-full.txt): the docs plus the full component source
- [Registry index](https://click-wheel.jackymo.me/r/registry.json)

## Quick reference

```tsx
import { ClickWheel } from "click-wheel";

<ClickWheel.Root
  value={seconds}
  onValueChange={setSeconds}
  max={duration}
  unitsPerTurn={60}
  detent={5}
>
  <ClickWheel.Ring aria-label="Playback position">
    <ClickWheel.Rotor />
  </ClickWheel.Ring>
  <ClickWheel.Center aria-label="Play" onClick={togglePlay}>
    <PlayIcon />
  </ClickWheel.Center>
</ClickWheel.Root>
```

- Parts have no default visual styles. State: `data-dragging` (a pointer holds the ring), `data-coasting` (coasting after release), `data-disabled`, `--click-wheel-fraction` (0–1), `--click-wheel-turns` (laps from min), `--click-wheel-rotation` (deg). `className` and `style` may be functions of `{ value, dragging, coasting, disabled }`. Every part takes a `render` prop.
- Gearing: `unitsPerTurn` sets how far one revolution moves the value. `detent` sets the units between haptic ticks. `inertia` (off by default) keeps the wheel spinning after a flick; `decelerationRate` (0.998) is the velocity kept per millisecond.
- Callbacks: `onValueChange` on every change, `onValueCommitted` once per completed interaction, `onInteractionChange` across pointer, scroll, keyboard and coasting (including cancellation), `onDraggingChange` when a pointer starts or stops dragging, `onTick` per detent.
- Haptics: Vibration API on Android; the switch trick on iOS 17.4–26.4; on iOS 26.5+ only real taps vibrate, so put `<HapticTap />` inside the center button.
