Color Picker
Accessible color selection with multiple color formats, palettes, tokens, eyedropper, contrast checks, and controlled commit flow.
ColorPicker provides a compact trigger or an always-visible inline editor. It combines a saturation/brightness area, hue and opacity sliders, text input, presets, recent colors, design-token swatches, an optional browser eyedropper, and contrast information.
Basic usage
import { ColorPicker } from '@mosmox/ui';
<ColorPicker label="Brand color" defaultValue="#003231" />The default picker opens from a trigger. Select a point in the color area, adjust hue or opacity, or enter a value directly.
Controlled usage and commit lifecycle
Use value and onChange when the parent owns the live value. onChange is emitted for every valid interaction. Use onCommit for persistence and onCancel for reverting an open edit session.
const [color, setColor] = useState('#003231');
<ColorPicker
value={color}
onChange={setColor}
onCommit={(next) => saveThemeColor(next)}
onCancel={() => console.log('Color edit cancelled')}
onInvalid={(raw) => console.warn('Invalid color:', raw)}
aria-label="Theme color"
/>onCommit also records the value in the internal recent-color list. A valid text value is committed on Enter or blur. Invalid text remains visible, receives aria-invalid, shows invalidMessage, and invokes onInvalid.
Supported formats
format controls the string emitted by onChange and onCommit. Input parsing accepts HEX (#rgb, #rgba, #rrggbb, #rrggbbaa), RGB/RGBA, HSL/HSLA, and HSB/HSV notation.
<ColorPicker format="hex" defaultValue="#12b76a" />
<ColorPicker format="hex8" defaultValue="#2e90facc" showAlpha />
<ColorPicker format="rgb" defaultValue="rgb(46, 144, 250)" />
<ColorPicker format="rgba" defaultValue="rgba(46, 144, 250, 0.7)" showAlpha />
<ColorPicker format="hsl" defaultValue="hsl(210, 82%, 58%)" />
<ColorPicker format="hsla" defaultValue="hsla(210, 82%, 58%, 0.7)" showAlpha />
<ColorPicker format="hsb" defaultValue="hsb(210, 82%, 98%)" />
<ColorPicker format="hsva" defaultValue="hsva(210, 82%, 98%, 0.7)" showAlpha />| Format | Example output | Alpha |
|---|---|---|
hex | #2e90fa | no |
hex8 | #2e90facc | hexadecimal channel |
rgb | rgb(46, 144, 250) | no |
rgba | rgba(46, 144, 250, 0.8) | decimal or percentage |
hsl | hsl(210, 82%, 58%) | no |
hsla | hsla(210, 82%, 58%, 0.8) | decimal or percentage |
hsb / hsv | hsb(210, 82%, 98%) | no |
hsba / hsva | hsba(210, 82%, 98%, 0.8) | decimal or percentage |
Use alphaFormat="percentage" when the alpha channel should be emitted as 80% instead of 0.8. Opaque formats intentionally omit alpha even when showAlpha is enabled.
Transparency and validation
Set allowTransparent to let users select the special transparent value. This is useful for overlays, borders, and optional theme values.
<ColorPicker
allowTransparent
defaultValue="transparent"
onInvalid={(value) => announce(`Invalid value ${value}`)}
invalidMessage="Use a HEX, RGB, HSL, HSV, or transparent value."
/>Palettes, presets, recent colors, and tokens
swatches is the regular palette. presets is rendered before it and can contain labeled objects. Recent colors are enabled with showRecent; double-clicking a recent swatch invokes onSwatchRemove. allowCustomSwatch exposes an action that sends the current value to onSwatchAdd so the application can persist its own palette.
<ColorPicker
defaultValue="#12b76a"
swatchShape="square"
swatchSize={28}
showSwatchLabels
presets={[
{ value: '#003231', label: 'Brand dark' },
{ value: '#12b76a', label: 'Success' },
]}
recentColors={['#f79009', '#7f56d9']}
showRecent
allowCustomSwatch
onSwatchAdd={(value) => saveRecentColor(value)}
onSwatchRemove={(value) => removeRecentColor(value)}
/>tokenOptions resolves theme values from CSS custom properties. A string such as "primary" resolves --mm-color-primary; pass { token: '--app-brand-color', value: '#12b76a' } when the application needs an explicit value.
<ColorPicker
tokenOptions={[
'primary',
'danger',
{ token: '--app-brand-color', label: 'Brand' },
]}
/>EyeDropper and contrast
showEyeDropper adds a native screen-color picker where the browser supports the EyeDropper API. The control remains disabled when the API is unavailable. showContrast displays the WCAG contrast ratio against contrastAgainst.
<ColorPicker
showEyeDropper
showContrast
contrastAgainst="#ffffff"
onChange={(value) => setForeground(value)}
/>The ratio is informational; the component does not reject colors based on a contrast threshold. The application can use the emitted value to enforce its own AA/AAA policy.
Layout, sizing, and popover behavior
size supports sm, default, and lg. inline keeps the panel open. placement chooses the popover side. portal renders it in document.body, which helps when the picker is inside an overflow-hidden container. popoverWidth accepts pixels or any CSS length.
<ColorPicker size="sm" defaultValue="#2e90fa" />
<ColorPicker size="default" defaultValue="#12b76a" />
<ColorPicker size="lg" defaultValue="#7f56d9" />
<ColorPicker inline label="Inline editor" defaultValue="#f79009" />
<ColorPicker placement="right" portal popoverWidth={320} />closeOnEscape restores the value that was active when the popover opened and calls onCancel. closeOnOutsideClick controls dismissal when clicking outside. Both are enabled by default. disabled prevents all interaction; readOnly shows the value without opening the editor.
Accessibility and keyboard input
The trigger exposes aria-haspopup="dialog" and aria-expanded. The saturation/brightness area is a keyboard slider: focus it and use Arrow keys; hold Shift for larger steps. Hue, opacity, and text input use native labeled controls. Escape cancels the current session when enabled. Provide aria-label when the visible label is not sufficient context.
API reference
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | Controlled current color. |
defaultValue | string | #003231 | Initial color. |
onChange | (value: string) => void | — | Fires for every valid color change. |
onCommit | (value: string) => void | — | Fires when a valid value is committed or selected. |
onCancel | () => void | — | Fires when Escape cancels the open edit session. |
onInvalid | (value: string) => void | — | Fires when text input cannot be parsed. |
invalidMessage | ReactNode | Enter a valid color value. | Validation message. |
onOpenChange | (open: boolean) => void | — | Fires when the popover opens or closes. |
label | ReactNode | — | Visible label. |
aria-label | string | Color picker | Accessible name. |
format | hex | hex8 | rgb | rgba | hsl | hsla | hsb | hsba | hsv | hsva | hex | Output and preferred input format. |
alphaFormat | decimal | percentage | decimal | Alpha representation for alpha-aware formats. |
size | sm | default | lg | default | Trigger size. |
inline | boolean | false | Keeps the panel visible. |
showAlpha | boolean | true | Shows opacity control. |
showInput | boolean | true | Shows text input. |
showSwatches | boolean | true | Shows palette and presets. |
swatches | ColorPickerPreset[] | built-in palette | Palette values or labeled entries. |
presets | ColorPickerPreset[] | [] | Entries shown before the regular palette. |
recentColors | string[] | [] | Initial recent values. |
showRecent | boolean | false | Shows recent colors. |
onSwatchAdd | (value: string) => void | — | Receives the current value from Add current color. |
onSwatchRemove | (value: string) => void | — | Receives a recent value on double-click. |
swatchShape | circle | square | circle | Swatch shape. |
swatchSize | number | string | 22 | Swatch width and height. |
showSwatchLabels | boolean | false | Shows the palette heading and titles. |
allowCustomSwatch | boolean | false | Shows the Add current color action. |
allowTransparent | boolean | false | Allows transparent. |
showEyeDropper | boolean | false | Shows the browser EyeDropper action. |
showContrast | boolean | false | Shows the calculated contrast ratio. |
contrastAgainst | string | #ffffff | Comparison color for contrast. |
tokenOptions | ColorPickerTokenOption[] | [] | CSS-token names or explicit token values. |
placement | top | bottom | left | right | bottom | Popover placement. |
closeOnEscape | boolean | true | Escape closes and cancels. |
closeOnOutsideClick | boolean | true | Outside click closes the popover. |
portal | boolean | false | Renders the popover in document.body. |
popoverWidth | number | string | 248 | Popover width. |
disabled | boolean | false | Disables interaction. |
readOnly | boolean | false | Prevents editing and opening. |
className | string | — | Additional root class. |
style | CSSProperties | — | Additional root styles. |
ColorPickerPreset is string | { value: string; label?: ReactNode }. ColorPickerTokenOption is string | { token: string; value?: string; label?: ReactNode }.