Color picker
A swatch that grows into a picker with format morphing, eyedropper, saved swatches, and contrast readout.
npm install https://animui.stracture.net/__local/package.tgz- Theme editors and brand settings where users choose an exact color.
- Design tools that need hex, RGB, HSL, and OKLCH input plus opacity.
- Any color choice where contrast against a background should be visible while picking.
- Use segmented-control or radio-group when the choice is between a few fixed colors.
- Use input for a plain hex field with no visual picking.
- Use chip-group for tagging items with a small preset palette.
Installation
Install animui once, then import any component or block from its typed package entry.
React 19 and React DOM 19 are required. The package includes Free and Pro entries, styles and TypeScript declarations.
npm install https://animui.stracture.net/__local/package.tgzLoad the stylesheet once at your app root, then use the typed component import:
import 'animui/styles.css';
import { ColorPicker } from 'animui/color-picker';Read the Code tab for the implementation files and the API reference below for required props.
Download animui 0.3.0 · Agent guideimport { useState } from "react";import { ColorPicker } from "animui/color-picker";import type { ColorSwatch } from "animui/color-picker"; export function BrandColor() { const [color, setColor] = useState("#2F6BFF"); const [swatches, setSwatches] = useState<ColorSwatch[]>([ { id: "ink", color: "#17171A" }, { id: "sky", color: "#3A8DFF" }, ]); return ( <ColorPicker label="Accent" value={color} onValueChange={setColor} background="#FFFFFF" swatches={swatches} onSwatchesChange={setSwatches} /> );}API reference
3 parts. The first is the root.
ColorPicker
A swatch trigger that grows into a picker with a saturation area, hue and opacity sliders, a typed value, contrast readout, and saved swatches.
valuestring–Controlled color in hex, rgb(), hsl(), or oklch().defaultValuestring"#2F6BFF"Uncontrolled starting color.onValueChange(hex: string) => void–Receives the color as uppercase hex, with two alpha digits when it is not opaque.backgroundstring"#FFFFFF"The background the color will sit on, for the WCAG contrast readout.labelstring"Color"Name shown on the swatch, such as "Accent".swatchesColorSwatch[]–Controlled saved swatches: { id, color }.defaultSwatchesColorSwatch[]–Uncontrolled starting swatches. Defaults to none.onSwatchesChange(swatches: ColorSwatch[]) => void–Called when swatches are added, reordered, or removed.maxSwatchesnumber7Most saved swatches. Saving past it drops the oldest.defaultFormat"hex" | "rgb" | "hsl" | "oklch""hex"Format shown in the text field first.classNamestring–Extra class on the root.parseColor
Reads hex, rgb(), hsl(), and oklch() in modern or comma syntax into { h, s, v, a }. Returns null for anything else.
inputRequiredstring–Color text.huenumber0Hue to keep for grays, where hue is undefined.toHex
Formats { h, s, v, a } as uppercase hex, adding alpha digits below full opacity.
hsvaRequiredHsva–Hue in degrees, saturation, value, and alpha from 0 to 1.- Arrow keys
- Move the saturation and brightness thumb in 2D, or the focused hue or opacity slider; Shift takes steps of ten.
- PageUporPageDown
- Step a slider by ten.
- HomeorEnd
- Move a slider to its minimum or maximum; in the swatch row, jump to the first or last swatch.
- Enter
- Applies the typed value in the text field; an invalid value shakes the field and shows an error.
- Alt+ArrowLeftorArrowRight
- Moves the focused swatch.
- DeleteorBackspace
- Removes the focused swatch.
- Escape
- Discards a typed draft first, then closes the panel and returns focus to the trigger.
- The trigger has aria-haspopup="dialog" and aria-expanded; the panel is a labelled dialog that turns inert while closing.
- The area thumb is a role="slider" with aria-roledescription="2D slider" and a value text naming saturation and brightness; hue and opacity are sliders with degree and percent value texts.
- The text field sets aria-invalid and points to a polite error message; the contrast ratio and its WCAG grade are also written out for screen readers.
- Saved swatches are a horizontal listbox with a roving tabindex, aria-selected on the current color, and labels that explain move and delete.
- The panel grows out of the swatch with an animated clip-path inset on a spring, and its drop shadow follows the clipped shape.
- Thumbs chase the pointer on a quick spring with slight bounce, and the contrast ratio counts to its new value.
- The format button morphs the text between hex, RGB, HSL, and OKLCH with text-morph; swatches pop in and reorder with layout springs.
- Reduced motion jumps the thumbs, fades the panel instead of clipping it, and skips the format morph and shake.
- The panel is min(19rem, 100vw - 32px) wide and opens down and to the right of the swatch, so leave room there.
- Below 360px viewport width the "against background" caption hides to keep the contrast row on one line.
- The area and sliders use touch-action: none with pointer capture, so dragging on touch never scrolls the page.
- Colors are converted in plain math (HSV, HSL, OKLCH) with no color library.
- The panel mounts only while open, and a ResizeObserver measures it for the clip-path animation.
- Thumbs animate motion values, so dragging does not re-render the slider tracks.
Notes for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Use for picking a single brand or theme color with an alpha channel. onValueChange always returns hex; parse it elsewhere if you need another format.
- Pass the real surface color as background so the contrast readout reflects where the color will be used.
- The eyedropper button appears only where window.EyeDropper exists (Chromium desktop).
- Imports TextMorph from the animui text-morph component, so install that alongside it.
The full library index for assistants is at /llms.txt.