Color Picker
- Stable
- WCAG 2.2 evidence
- RTL
Picks a colour. Built on React Aria ColorPicker, which keeps every part
in sync: a saturation / brightness ColorArea, hue and alpha ColorSliders, an eyedropper (where the browser supports
it), a format menu with hex or RGB / HSL channel fields plus an alpha field, and preset rows (ColorSwatchPicker). Every drag has keyboard and typing alternatives (WCAG 2.1.1, 2.5.7): arrow keys step the area and sliders (Shift or
Page Up / Page Down for larger steps, Home / End on the sliders), and the fields take typed values. The area and
sliders expose their channels and values as text ("Saturation 97%, Brightness 52%", "Hue 162°, green") and presets
are named by colour name and hex value, so colour is never the only identifier; the selected preset has a ring
(1.4.1, 1.4.11, 4.1.2). Consumer duties: preset names, translated labels, and where the picker lives (inline or in ColorInput's popover).
import { ColorPicker } from "@nexera-ui/react";- 5
- examples
- 20
- props
- 3
- live controls
- 1
- platform
- 7
- WCAG criteria
- 1
- block uses it
Try every prop. Copy the code.
Change the props and the code updates. Check light and dark, LTR and RTL, and phone width.
import { ColorPicker } from "@nexera-ui/react";
<ColorPicker />Examples 4
The same examples as Storybook, rendered live. Open Code to copy one.
Compact
Figma Mode=Compact: the preset rows only.
import { ColorPicker } from "@nexera-ui/react";
const brandColors: readonly ColorPreset[] = [
{ color: "#04855D", name: "Emerald 600" },
{ color: "#2563EB", name: "Blue 600" },
{ color: "#D97706", name: "Amber 600" },
{ color: "#7C3AED", name: "Violet 600" },
{ color: "#0E7490", name: "Cyan 700" },
{ color: "#DB2777", name: "Pink 600" },
{ color: "#C2410C", name: "Orange 700" },
{ color: "#6B7280", name: "Gray 500" },
];
const recentColors: readonly ColorPreset[] = [
{ color: "#DC2626", name: "Danger" },
{ color: "#F59E0B", name: "Warning" },
{ color: "#3B82F6", name: "Info" },
{ color: "#8B5CF6", name: "Leave" },
];
<ColorPicker
aria-label="Brand color"
defaultValue="#04855D"
presets={brandColors}
recentColors={recentColors}
onCustomColor={() => undefined}
mode="compact"
/>;
Rgb fields
RGB channel fields (the format menu also offers HSL).
import { ColorPicker } from "@nexera-ui/react";
const brandColors: readonly ColorPreset[] = [
{ color: "#04855D", name: "Emerald 600" },
{ color: "#2563EB", name: "Blue 600" },
{ color: "#D97706", name: "Amber 600" },
{ color: "#7C3AED", name: "Violet 600" },
{ color: "#0E7490", name: "Cyan 700" },
{ color: "#DB2777", name: "Pink 600" },
{ color: "#C2410C", name: "Orange 700" },
{ color: "#6B7280", name: "Gray 500" },
];
const recentColors: readonly ColorPreset[] = [
{ color: "#DC2626", name: "Danger" },
{ color: "#F59E0B", name: "Warning" },
{ color: "#3B82F6", name: "Info" },
{ color: "#8B5CF6", name: "Leave" },
];
<ColorPicker
aria-label="Brand color"
defaultValue="#04855D"
presets={brandColors}
recentColors={recentColors}
onCustomColor={() => undefined}
defaultFormat="rgb"
/>;
Controlled
Controlled: the selected colour is shown as text next to the picker.
import { useState } from "react";
import { type Color } from "react-aria-components";
import { ColorPicker } from "@nexera-ui/react";
const brandColors: readonly ColorPreset[] = [
{ color: "#04855D", name: "Emerald 600" },
{ color: "#2563EB", name: "Blue 600" },
{ color: "#D97706", name: "Amber 600" },
{ color: "#7C3AED", name: "Violet 600" },
{ color: "#0E7490", name: "Cyan 700" },
{ color: "#DB2777", name: "Pink 600" },
{ color: "#C2410C", name: "Orange 700" },
{ color: "#6B7280", name: "Gray 500" },
];
const recentColors: readonly ColorPreset[] = [
{ color: "#DC2626", name: "Danger" },
{ color: "#F59E0B", name: "Warning" },
{ color: "#3B82F6", name: "Info" },
{ color: "#8B5CF6", name: "Leave" },
];
export function Controlled() {
const [value, setValue] = useState<string | Color>("#2563EB");
return (
<div className="flex flex-wrap items-start gap-4">
<ColorPicker
aria-label="Brand color"
defaultValue="#04855D"
presets={brandColors}
recentColors={recentColors}
onCustomColor={() => undefined}
value={value}
onChange={setValue}
/>
<p className="m-0 text-body-small text-secondary">
{typeof value === "string" ? value : value.toString("hexa")}
</p>
</div>
);
}
Right to left
Right-to-left: the sliders and the area follow the reading direction; hex values stay left-to-right.
import { ColorPicker } from "@nexera-ui/react";
const brandColors: readonly ColorPreset[] = [
{ color: "#04855D", name: "Emerald 600" },
{ color: "#2563EB", name: "Blue 600" },
{ color: "#D97706", name: "Amber 600" },
{ color: "#7C3AED", name: "Violet 600" },
{ color: "#0E7490", name: "Cyan 700" },
{ color: "#DB2777", name: "Pink 600" },
{ color: "#C2410C", name: "Orange 700" },
{ color: "#6B7280", name: "Gray 500" },
];
const recentColors: readonly ColorPreset[] = [
{ color: "#DC2626", name: "Danger" },
{ color: "#F59E0B", name: "Warning" },
{ color: "#3B82F6", name: "Info" },
{ color: "#8B5CF6", name: "Leave" },
];
<ColorPicker
aria-label="لون العلامة"
defaultValue="#04855D"
presets={brandColors}
recentColors={recentColors}
onCustomColor={() => undefined}
presetsLabel="ألوان العلامة"
recentLabel="الأخيرة"
/>;
Props 20
Press "Try it" on a card to load that prop into the playground.
20 props shown
modeNexera"full" | "compact"Layout: full adds the saturation area, hue and alpha sliders, eyedropper and value fields above the
presets; compact shows only the preset rows.
valueNexerastring | ColorThe colour (controlled), as a CSS string or a React Aria Color. Pair it with onChange.
defaultValueNexerastring | ColorThe initial colour (uncontrolled).
onChangeNexera(color: Color) => voidCalled with the new Color on every change (each step of a drag, key press, preset or committed field).
presetsNexerareadonly ColorPreset[]Colours of the first preset row. The row is shown when not empty.
presetsLabelNexerastringHeading of the first preset row, which names its listbox. Translate it.
recentColorsNexerareadonly ColorPreset[]Colours of the second row. Shown when not empty.
recentLabelNexerastringHeading of the second row. Translate it.
onCustomColorNexera(color: Color) => voidShows the "+" button after the recent colours and is called with the current
colour when it is pressed: save it as a custom colour, or switch a compact picker to full.
customColorLabelNexerastringAccessible name of the "+" button. Translate it.
formatNexera"hex" | "rgb" | "hsl"Format of the value fields: hex, rgb or hsl.
defaultFormatNexera"hex" | "rgb" | "hsl"Initial format of the value fields (uncontrolled).
onFormatChangeNexera(format: ColorPickerFormat) => voidCalled when the user picks another format.
formatLabelNexerastringAccessible name of the format menu. Translate it.
hexLabelNexerastringAccessible name of the hex field. Translate it. (The channel and alpha fields use React Aria's localised channel names.)
eyeDropperLabelNexerastringAccessible name of the eyedropper button, shown only in browsers that support the EyeDropper API. Translate it.
classNameNexerastringExtra classes for the panel, merged last so they win over the defaults.
styleNexeraCSSPropertiesInline style for the panel.
aria-labelNexerastringAccessible name of the picker, for example "Brand color". Translate it.
aria-labelledbyNexerastringId(s) of visible element(s) that name the picker; wins over aria-label.
Id(s) of visible element(s) that name the picker, such as the label of the field that opened it.
* Required. React Aria props shown are the ones most apps use; the component accepts the rest of its React Aria props too.
Accessible by default.
Built on React Aria, and covered by the WCAG 2.2 evidence generated on every build.
WCAG 2.2 evidence
5 direct · 2 supporting- 1.3.1Info and RelationshipsLevel A · tested directly
- 1.4.1Use of ColorLevel A · tested directly
- 1.4.11Non-text ContrastLevel AA · supporting test
- 2.1.1KeyboardLevel A · tested directly
- 2.5.7Dragging MovementsLevel AA · tested directly
- 2.5.8Target Size (Minimum)Level AA · supporting test
- 4.1.2Name, Role, ValueLevel A · tested directly
Fits any width.
Nexera components respond to the space they are given. Drag the corner of the frame, or pick a width.
Styling hooks
Pass className to add Tailwind classes (merged last). State is exposed as data attributes, so you can style it with variants like data-pressed:.
data-disableddata-hovereddata-presseddata-selected
<ColorPicker className="data-disabled:opacity-90 shadow-sm" />Used in blocks
Related components
- CalendarDayOne day of a {@link CalendarMonth } grid, built on React Aria `CalendarCell`: a `gridcell` whose button is named by the full, localised date ("Wednesday, October 14, 2026"), with `aria-selected`, `aria-disabled` and the "today" and range descriptions read by screen readers (WCAG 1.3.1, 4.1.2).
- CalendarMonthA month calendar for picking a date or a date range: header with previous / next buttons and the localised month name, weekday row, and six weeks of `CalendarDay`s.
- CheckboxThe bare 18 px checkbox: one independent yes/no choice applied on submit, or a row selector in a table, list or tree.
- CheckboxCardA large checkbox option with an icon, a title and a description, for a few options that need explanation (notification channels, benefits).
- CheckboxFieldA checkbox with a label and optional helper text: the box (the same element as `Checkbox`) followed by the label and description, applied on submit.
- ColorInputA hex colour field with a swatch and a picker popover.
- ColorTokenCardDocumentation card for one colour token: a 96 px colour sample with an "Aa" text sample, then the name, token path, hex value and contrast note as text.
- ComboboxA text field with a filtered list of options.