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 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-visible ring; 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.

Show 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

Presets
Show 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 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 passthrough aria-label when the field’s label alone doesn’t say enough (e.g. multiple swatches on one page).
  • hint / error are wired to the hex field via aria-describedby; error also sets aria-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 error without fixing the underlying value — aria-invalid on 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).”