# Color Picker

Choose a hex color with a swatch, hue slider, and channel fields.

Brand color field

[Complete TSX file](/examples/color-picker/default.tsx)

```tsx
"use client";

import { ColorPicker } from "@/siteplane/components/color-picker";
import {
  Field,
  FieldDescription,
  FieldLabel,
} from "@/siteplane/components/field";

export default function Example() {
  return (
    <Field className="w-full max-w-sm">
      <FieldLabel>Brand color</FieldLabel>
      <ColorPicker defaultValue="#6366f1" />
      <FieldDescription>
        Used for buttons, links and focus rings.
      </FieldDescription>
    </Field>
  );
}
```

## Installation

Complete [one-time setup](/docs/installation/) first.

```bash
pnpm dlx shadcn@4.18.0 add @siteplane/color-picker
```

With npm: `npx shadcn@4.18.0 add @siteplane/color-picker`. [Registry JSON](/registry/color-picker.json) lists source files and dependencies.

For this page’s examples, also install:

```bash
pnpm dlx shadcn@4.18.0 add @siteplane/button @siteplane/form @siteplane/input
```

Field is installed with Input.

## Usage

```tsx
import { ColorPicker } from "@/siteplane/components/color-picker";

<ColorPicker aria-label="Brand color" />;
```

## Controlled color

The callback emits a lowercase hex string.

Controlled color

[Complete TSX file](/examples/color-picker/controlled.tsx)

```tsx
"use client";

import { ColorPicker } from "@/siteplane/components/color-picker";
import { Field, FieldLabel } from "@/siteplane/components/field";
import { useState } from "react";

export default function Example() {
  const [color, setColor] = useState("#6366f1");
  return (
    <Field className="w-full max-w-sm">
      <FieldLabel>Brand color</FieldLabel>
      <ColorPicker value={color} onValueChange={setColor} />
    </Field>
  );
}
```

## Sizes and swatch-only trigger

Hide the text value with `showValue={false}`; keep a meaningful accessible label. `disabled` blocks the picker and leaves its value out of form submission.

Color picker sizes and swatch-only trigger

[Complete TSX file](/examples/color-picker/sizes.tsx)

```tsx
"use client";

import { ColorPicker } from "@/siteplane/components/color-picker";

const sizes = [
  { name: "small", size: "sm" },
  { name: "medium", size: "md" },
  { name: "large", size: "lg" },
  { name: "extra large", size: "xl" },
] as const;

export default function Example() {
  return (
    <div className="flex flex-wrap items-center gap-3">
      {sizes.map(({ name, size }) => (
        <ColorPicker
          key={size}
          aria-label={`Brand color, ${name}`}
          size={size}
          defaultValue="#6366f1"
          showValue={false}
        />
      ))}
      <ColorPicker aria-label="Accent color" defaultValue="#6366f1" disabled />
    </div>
  );
}
```

## Custom color swatch

Set `variant="swatch"` to draw the trigger as a [Color Swatch Picker](/docs/components/color-swatch-picker/) swatch, for a palette that ends in a custom color. Pressing the swatch opens the picker. Pass `selected` while the custom color is the one chosen in the row, and `indicator` to show the selection as a check or a ring, as on Color Swatch Picker. `onOpenChange` lets the row choose the custom color as soon as the picker opens.

Palette that ends in a custom color

[Complete TSX file](/examples/color-picker/custom.tsx)

```tsx
"use client";

import { ColorPicker } from "@/siteplane/components/color-picker";
import { ColorSwatchPicker } from "@/siteplane/components/color-swatch-picker";
import { useState } from "react";

const presets = [
  { value: "#6366f1", label: "Indigo", color: "#6366f1" },
  { value: "#22c55e", label: "Green", color: "#22c55e" },
  { value: "#f59e0b", label: "Amber", color: "#f59e0b" },
  { value: "#f43f5e", label: "Rose", color: "#f43f5e" },
];

export default function Example() {
  const [color, setColor] = useState("#6366f1");
  const [custom, setCustom] = useState("#0ea5e9");
  const isPreset = presets.some((preset) => preset.value === color);

  return (
    <div className="flex flex-wrap items-center gap-2">
      <ColorSwatchPicker
        aria-label="Accent color"
        options={presets}
        size="sm"
        value={color}
        onValueChange={setColor}
      />
      <ColorPicker
        aria-label={`Custom color ${custom.toUpperCase()}`}
        selected={!isPreset}
        size="sm"
        value={custom}
        variant="swatch"
        onOpenChange={(open) => {
          if (open) setColor(custom);
        }}
        onValueChange={(value) => {
          setCustom(value);
          setColor(value);
        }}
      />
    </div>
  );
}
```

## Form integration

Inside a `Field`, the picker submits its lowercase hex value under the field’s `name`. It always holds a color, so `required` never blocks submission.

Color picker in a form

[Complete TSX file](/examples/color-picker/form.tsx)

```tsx
"use client";

import { Button } from "@/siteplane/components/button";
import { ColorPicker } from "@/siteplane/components/color-picker";
import { Field, FieldLabel } from "@/siteplane/components/field";
import { Form } from "@/siteplane/components/form";

export default function Example() {
  return (
    <Form
      className="grid w-full max-w-sm gap-4"
      onSubmit={(event) => {
        event.preventDefault();
      }}
    >
      <Field name="brandColor">
        <FieldLabel>Brand color</FieldLabel>
        <ColorPicker defaultValue="#22c55e" />
      </Field>
      <Button type="submit">Save</Button>
    </Form>
  );
}
```

## API reference

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| value / defaultValue | string | defaultValue: "#000000" | Controlled color or uncontrolled initial hex; an omitted hash is accepted. |
| onValueChange | (value: string) => void | — | Emits lowercase hex. |
| open / defaultOpen | boolean | uncontrolled / false | Controlled or initial open state of the picker. |
| onOpenChange | (open: boolean) => void | — | Called when the picker opens or closes. |
| showValue | boolean | true | Displays the current value beside the swatch. The swatch variant never shows it. |
| variant | default \| swatch | default | default is an outlined button with the color and its hex value. swatch is a bare swatch of the current color, drawn like a Color Swatch Picker swatch. |
| selected | boolean | false | Swatch variant only: marks the swatch as the chosen color of its row. It shows the indicator and sets aria-current. |
| indicator | check \| ring | check | Swatch variant only: how a selected swatch shows it, as on Color Swatch Picker. |
| size | sm \| md \| lg \| xl | provider / lg | Control dimensions. |
| disabled | boolean | false | Disables trigger, fields, and submitted value; a disabled Field also disables the picker. |
| name / form | string | — | Hidden input name and associated form id; a Field name takes precedence. |
| readOnly | boolean | false | Shows and submits the color; the controls open for reading and copying, but the color does not change. |
| required | boolean | false | Sets required on the hidden form input. The picker always holds a color, so it never blocks submission. |
| id / className / style / tabIndex | string / string / CSSProperties / number | — | Applied to the visible trigger. |
| aria-label / aria-labelledby / aria-describedby / aria-invalid | string / string / string / AriaAttributes[aria-invalid] | Generated color label if unnamed | Applied to the trigger; inside a Field, FieldLabel, FieldDescription and FieldError are connected automatically. |
| labels | Partial<ColorPickerLabels> | English | Accessible names of the controls in the popover; see the keys below. |

The keys of `labels`, each with its English default, are `controls` (Color controls, the popover), `saturation` (Color saturation and brightness), `hue` (Color hue), `hex` (Hex color value), `copy` (Copy hex value), `copied` (Copied hex value, while the check shows), `copyFailed` (Copy unavailable, when the clipboard refuses), and `red`, `green` and `blue` (R color channel, G color channel, B color channel). The letters R, G and B beside the channel fields stay as they are.

Exported types: `ColorPickerProps`, `ColorPickerLabels`. These describe the contracts above.

[Read the installed source](/source/color-picker).

## Usage notes

Inside a Field, FieldLabel names the trigger and clicking it focuses the trigger; outside a Field, pass `aria-label` or `aria-labelledby`. The picker takes only the props above; it owns its hidden form input. Use `readOnly` to show a color that cannot change and `disabled` to switch the picker off. Invalid hex falls back to the normalized default, then black. This control does not expose alpha, locale, or popup placement props.
