ColorPicker
A native colour swatch with a synced hex field, preset swatches and an optional eyedropper.
Last updated
Uses JavaScript
Keeps the native colour input and the hex field in sync both ways, applies
a chosen preset swatch to both, and wires the eyedropper where the browser
has one. Every committed pick fires one change on the hex field, the input
that carries name.
Without JS: The native colour input and the hex field each still work on their own, but don't stay in sync. Preset swatches and the eyedropper are hidden, since they only work through the script.
Show codeHide code
<ColorPicker label="Accent color" name="accent" value="#3b82f6" />Add
npx @ava-ui/apogee add color-picker
Pulls in Field (label, hint, error scaffold).
Usage
---
import ColorPicker from '@/components/apogee/ColorPicker/ColorPicker.astro'
---
<ColorPicker label="Accent color" name="accent" value="#3b82f6" />
Anatomy
- Label / hint / error — from
Field. - Swatch — native
<input type="color">; opens the system color picker. - Hex field — text input, submits under
name; kept in sync with the swatch.
API
@composable — exposed to Content Editors in AVA. Any other attribute passes
through to the swatch (<input type="color">) — e.g. disabled, or an
aria-label override (it defaults to "Color picker").
| Prop | Type | Default | Description |
|---|---|---|---|
id |
string |
auto-generated | Id for the hex field; wires Field’s label and aria-describedby. |
label |
string |
— | Field label. |
hint |
string |
— | Helper text under the control; it stays when error is set. |
error |
string |
— | Error text; sets aria-invalid on the hex field and renders via role="alert". |
name |
string |
— | Name attribute for the hex text field (this is what submits). |
value |
string |
'#3b82f6' |
Initial colour for both inputs. A form default, not a style. |
required |
boolean |
false |
Marks the hex field (the one that submits) required. |
swatches |
string[] |
— | Preset colours as selectable swatches (native radios); picking one sets both inputs. |
presets |
string[] |
— | Suggestions for the native picker via <datalist> (zero JS; Chromium shows them in its popup). |
eyedropper |
boolean |
false |
A button that samples a colour from the screen; removed where the browser has no EyeDropper. |
class |
string |
— | Extra classes, passed to the Field wrapper. |
States
- Default — swatch + hex field, in sync.
- Focus — the hex field shows a visible
focus-visiblering; the swatch uses the browser’s native focus indicator. - Hint — helper text under the field.
- Error — hex field border turns
--border-critical,aria-invalid="true", and the error text shows under the hint.
Used for buttons and links.
Enter a valid hex color (#RRGGBB).
Show codeHide code
<ColorPicker label="Brand color" hint="Used for buttons and links." />
<ColorPicker label="Brand color" value="#ff0000zz" error="Enter a valid hex color (#RRGGBB)." />Swatches, presets and eyedropper
Show codeHide code
<ColorPicker label="Label colour" name="label" swatches={['#0f766e', '#2563eb', '#7c3aed', '#db2777', '#ea580c']} eyedropper />
<ColorPicker label="Accent" presets={['#0f766e', '#2563eb', '#db2777']} />Examples
Without a label (still pass one where possible — see Accessibility):
<ColorPicker name="highlight" value="#22c55e" />
Required field, wired into a form:
Show codeHide code
<ColorPicker label="Theme color" name="theme" required />Accessibility
| Key | Action |
|---|---|
Tab |
Moves from the swatch to the hex field, the eyedropper, then the presets. |
Enter Space |
Open the system color picker from the swatch, or start the eyedropper. |
Esc |
Cancels the eyedropper and keeps the current color. |
← → ↑ ↓ |
Move between presets and select one. |
- The swatch has
aria-label="Color picker"by default — override it via a passthrougharia-labelwhen the field’slabelalone doesn’t say enough (e.g. multiple swatches on one page). hint/errorare wired to the hex field viaaria-describedby;erroralso setsaria-invalid="true".- No JS: the swatch and hex field still each work independently — the
color picker opens natively, and the hex field still submits under
name— they just don’t sync live with each other. See the note above.
Tokens
| Token | Used for |
|---|---|
--border-neutral |
Swatch and hex field border |
--background-page |
Hex field background |
--foreground-neutral |
Hex field text |
--foreground-neutral-faded |
Hint text |
--border-critical / --foreground-critical |
Error border / error text |
--outline-color-focus |
Hex field focus ring |
Do / Don’t
- Do always pass
label— a bare swatch/hex pair isn’t self-describing without one. - Do validate the submitted hex value server-side; the hex field accepts any typed text, not just a valid hex string.
- Don’t rely on the swatch alone for keyboard or AT users — the hex field is the reliable keyboard path.
- Don’t clear
errorwithout fixing the underlying value —aria-invalidon its own isn’t a fix.
Content
- Label names what the color controls (“Accent color”), not the control itself (“Color”).
- Error copy states the expected format, e.g. “Enter a valid hex color (#RRGGBB).”