# Color picker

> Swatches with a selection ring that springs from swatch to swatch while the chosen swatch shrinks inside it, plus an optional pad: drag the thumb over saturation and brightness, slide the hue bar, and the before and after preview follows live.

- Type: Component (inputs)
- Access: Free, open source (MIT)
- Page: https://goodui.dev/native/components/color-picker
- Markdown: https://goodui.dev/native/components/color-picker.md
- Registry item: https://goodui.dev/native/r/color-picker.json
- Dependencies: react-native-gesture-handler, react-native-reanimated, react-native-svg
- Keywords: react native color picker, color swatches, hue saturation picker, hsv color pad, label color picker, theme color chooser expo

## When to use

- Tagging things with a color: calendars, labels, folders, habits, wallet cards.
- Letting people pick a brand or theme color, with the pad for exact colors.

## When not to use

- Choosing the app's own accent from a fixed set of names: a ChipGroup from chip or segmented-control reads better.
- Choosing among products that happen to differ by color (a phone in three finishes): use a ChipGroup with labels, color alone is not enough.

## Installation

With the shadcn CLI (needs a components.json in the Expo app), then `npx expo install --fix` so native dependencies match your Expo SDK. The foundation comes along the first time.

```bash
npx shadcn@latest add https://goodui.dev/native/r/color-picker.json
npx expo install --fix
```

The component lands in `components/goodui-native/color-picker/` and imports the foundation from `components/goodui-native/foundation/` with relative paths; it also installs locale.

Built-in strings follow `<GooduiLocaleProvider>` (one [language pack](https://goodui.dev/native/r/locale-tr.json) translates the whole kit); the `labels` prop overrides them for one instance.

## Usage

```tsx
import { useState } from "react";
import { ColorPicker } from "@/components/goodui-native/color-picker/color-picker";

export function CalendarColor() {
  const [color, setColor] = useState("#2F6FDB");
  return (
    <ColorPicker
      value={color}
      onValueChange={setColor}
      swatches={[
        { value: "#2F6FDB", label: "Blue" },
        { value: "#1F9D6B", label: "Green" },
        { value: "#E0A21B", label: "Amber" },
        { value: "#E5484D", label: "Red" },
        { value: "#8E4EC6", label: "Purple" },
      ]}
    />
  );
}
```

## Examples

### Pad always open, square swatches

```tsx
<ColorPicker custom="inline" shape="square" size="sm" swatches={brandColors} value={brand} onValueChange={setBrand} />
```

### Swatches only

```tsx
<ColorPicker custom="none" swatches={["#F2F2F2", "#1C1C1E", "#C7B299"]} defaultValue="#1C1C1E" accessibilityLabel="Finish" />
```

## API reference

### ColorPicker

`import { ColorPicker } from "@/components/goodui-native/color-picker/color-picker";`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `swatches` (required) | `ColorSwatch[]` | – | The swatches, as "#RRGGBB" strings or `{ value, label }` with a name for screen readers. |
| `value` | `string` | – | Selected color as "#RRGGBB" (controlled). |
| `defaultValue` | `string` | – | Starting color when uncontrolled. Defaults to the first swatch. |
| `onValueChange` | `(color: string) => void` | – | Called with "#RRGGBB" on a swatch tap, and when the finger lifts from the pad or the hue bar. |
| `custom` | `"none" \| "toggle" \| "inline"` | `"toggle"` | The custom color pad (saturation and brightness, a hue bar and a preview). `toggle` adds a custom swatch that opens it, `inline` always shows it, `none` leaves swatches only. |
| `size` | `"sm" \| "md"` | `"md"` | Swatch diameter 32 (`sm`) or 40 pt (`md`), always with a 44 pt touch target. |
| `shape` | `"circle" \| "square"` | `"circle"` | Round swatches, or rounded squares. |
| `haptic` | `boolean` | `true` | `false` silences the select haptic. |
| `accessibilityLabel` | `string` | – | Names the swatch group for screen readers. Same as `labels.color`. |
| `labels` | `Partial<ColorPickerLabels>` | – | Overrides for the built-in strings; a GooduiLocaleProvider pack sets them app-wide. |
| `style` | `StyleProp<ViewStyle>` | – | Style for the outer container. |
| `testID` | `string` | – | Identifier for end-to-end tests. |

## Accessibility

- Swatches are radios in a radiogroup named by accessibilityLabel (default "Color"); give swatches a label so they are read as names, otherwise the hex code is read.
- The custom swatch is a button ("Custom color", with the current custom hex) that reports expanded while the pad is open.
- The pad is adjustable: increment and decrement change brightness, and "More saturated" and "Less saturated" actions change saturation, in 5 % steps; its value reads "Saturation 80 percent, brightness 60 percent".
- The hue bar is adjustable in 5° steps with a value in degrees.
- On the web the pad and the hue bar are focusable sliders with aria-valuenow, min, max and valuetext: Left and Right change saturation, Up and Down brightness on the pad; arrows change the hue on the bar.
- Swatch touch areas are 44 pt whatever the swatch size. The preview is read as "Was #…, now #…".

## Motion

- The ring travels between swatches: the edges facing the new swatch lead on the snappy spring and the others follow on smooth, so it stretches across and settles, across rows too.
- The selected swatch shrinks to 78 % on the bouncy spring, opening a gap inside the ring; the old one grows back on snappy.
- The pad thumb and the hue thumb follow the finger 1:1 from touch down; the pad, the thumb fill and the preview recolor on the UI thread while dragging. A swatch tap moves the thumbs there on the smooth spring.
- The pad opened from the custom swatch drops in on the smooth spring.
- Reduced motion: the ring jumps, swatch scaling is a short timing, the thumbs jump to a swatch's color, and the pad appears in place.

## Haptics

- select when the color changes from a swatch, a pad or hue release, or a key
- haptic={false} silences it

## Performance

- Dragging updates shared values only; React renders once when the finger lifts, which is also when onValueChange fires.
- Gradients are react-native-svg linear gradients over a view whose hue is animated, so the pad costs one view and one svg.

## Notes for AI

- Colors are "#RRGGBB" strings (3-digit and lower case are accepted and normalized to upper case). onValueChange gets upper case "#RRGGBB".
- onValueChange fires when a drag ends, not during it. Use the value for saving; the live preview is internal.
- A value not among the swatches selects the custom swatch (custom="toggle") and shows inside it.
- Swatch colors are content: pass your palette. The component draws its own chrome from theme tokens.

## Related

- [Chip](https://goodui.dev/native/components/chip.md): Filter, choice and input chips: selecting one fills it with the accent while a check draws itself in, removing one shrinks it away, and a ChipGroup in single mode moves one elastic highlight from chip to chip.
- [Slider](https://goodui.dev/native/components/slider.md): Single and range sliders whose thumbs follow the finger 1:1 and settle onto the nearest step on release, with a value bubble that grows out of the thumb while dragging and optional step ticks that tick.
- [Segmented control](https://goodui.dev/native/components/segmented-control.md): Two to five views of the same thing with an elastic highlight that stretches toward the new segment, can be dragged, and ticks at every boundary. Includes a billing toggle.

## Guidance for AI tools

Color picker: Swatches with a selection ring that springs from swatch to swatch while the chosen swatch shrinks inside it, plus an optional pad: drag the thumb over saturation and brightness, slide the hue bar, and the before and after preview follows live. Use only the documented props. Keep accessibility, reduced motion and both color schemes intact when adapting it.

Full library index: https://goodui.dev/native/llms.txt
