<!-- Generated by scripts/gen-docs.mts from the JSDoc in registry/. Do not edit; run `pnpm run docs`. -->

# ColorField

A color on the Field contract: a swatch that opens the system color picker, next to the same color as hex text, kept in step both ways. Typing a whole hex (`#36f` or `#3366ff`) moves the swatch, leaving the text tidies it, and the form always gets `#rrggbb`.

```tsx
import { ColorField } from "@/components/ouro/color-field/color-field";
```

## Example

```tsx
<ColorField label="Accent color" name="accent" defaultValue="#3366ff" error={errors?.accent} />
<ColorField label="Tag color" value={color} onValueChange={setColor} />
```

## Use instead when

- Use `RadioGroup` instead when the colors come from a short fixed list, such as tag colors.

## Props

Type: `ColorFieldProps`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `className` | `string` |  | Layout only: margins, width, grid placement (`mt-4`). Appearance classes warn in development; style fields in your theme. |
| `defaultValue` | `string` | `"#000000"` | The color the field starts with, and goes back to when its form resets, as hex. |
| `description` | `ReactNode` |  | Supporting text under the label, read through `aria-describedby`. |
| `disabled` | `boolean` |  | Disables the swatch and the text, and fades the field. |
| `error` | `ReadonlyErrorMessages` |  | What is wrong, from your server action or client check. It shows under the field, which gets `aria-invalid`. A message is text or a React node (one with a link); an empty string or array means valid. |
| `hideLabel` | `boolean` |  | Hides the label visually; screen readers still read it. |
| `label` (required) | `string` |  | What the color is for ("Accent color"), shown above the field and read as the text input's name. Required: every control needs a name. To hide it visually, keep it and add `hideLabel`. |
| `name` | `string` |  | The form field name the color submits under, always as `#rrggbb`. |
| `onValueChange` | `((hex: string) => void)` |  | Called with the color as `#rrggbb` when it is picked, or typed as a whole hex. |
| `pickerLabel` | `string` | `"Pick a color"` | The name of the swatch that opens the system color picker. The swatch is a color input, which can only be named by label text, so Playwright's loose `getByLabel("Color")` also finds it when the field's label is in this name; find the field with `getByLabel("Color", { exact: true })` or `getByRole("textbox", { name: "Color" })`. Translate it with your app. |
| `ref` | `Ref<HTMLInputElement>` |  | The hex text input. |
| `required` | `boolean` |  | Marks the field required: it gets `aria-required`, and the label a marker. A color always has a value, so it never blocks a submit, even with the text cleared. |
| `value` | `string` |  | The color as hex (`#3366ff`, or short `#36f`), when you control it. Pair it with `onValueChange`. |

## Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

- `alpha`: Not supported by ColorField. ColorField takes `#rrggbb`, with no transparency.
- `color`: Not a prop. Ouro UI uses `value` or `defaultValue`: `<ColorField defaultValue="#ff0000">`.
- `errorMessage`: Not a prop. Ouro UI uses `error`: `<ColorField error="Pick a darker color.">`.
- `format`: Not a prop. ColorField takes and gives `#rrggbb`: `<ColorField defaultValue="#3366ff">`.
- `helperText`: Not a prop. Ouro UI uses `description`: `<ColorField description="...">`.
- `invalid`: Not a prop. `error` marks the field invalid: `<ColorField error="What is wrong">`.
- `isDisabled`: Not a prop. Ouro UI uses `disabled`: `<ColorField disabled>`.
- `isInvalid`: Not a prop. `error` marks the field invalid: `<ColorField error="What is wrong">`.
- `isRequired`: Not a prop. Ouro UI uses `required`: `<ColorField required>`.
- `onChange`: Not a prop. Ouro UI uses `onValueChange`, which gets the hex: `<ColorField onValueChange={(hex) => ...}>`.

## `className` is for layout only

Pass margins, width and grid placement (`mt-4`, `w-full`, `col-span-2`). Your classes always win over Ouro UI's: ColorField merges `className` last with `cn` (tailwind-merge), so a class that conflicts with its own replaces it.[^layout-classes]

Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (`hover:`, `sm:`) and any `!` are removed, it starts with `bg-`, `text-`, `border-`, `rounded-`, `shadow-`, `font-`, `ring-`, `from-`, `via-`, `to-`, `fill-` or `stroke-`, or is `border`, `rounded`, `shadow` or `ring`, or has a `dark:` variant. Text wrapping, overflow and table layout classes (`text-wrap`, `text-ellipsis`, `border-collapse`) are layout and do not warn.

Alignment classes (`text-center`) warn too: set alignment on a parent element.

## Types

### `ErrorMessage`

One error message: text, or a React element for a message that carries a link or other markup.

```ts
type ErrorMessage = string | ReactElement;
```

### `ReadonlyErrorMessages`

A read-only message view accepted by fields and Form; mutable input arrays remain valid.

```ts
type ReadonlyErrorMessages = ErrorMessage | readonly ErrorMessage[];
```

[^layout-classes]: test:registry/ouro/components/ouro/color-field/color-field.test.tsx::ColorField > forwards its ref to the text input and lets layout classes win on the root verify:testExists(registry/ouro/components/ouro/color-field/color-field.test.tsx::ColorField > forwards its ref to the text input and lets layout classes win on the root)
