ColorPicker

Selects a color through a visual picker and hexadecimal input.

import { ColorPicker } from "@usefragments/ui";Source

Preview

<ColorPicker
  label="Brand Color"
  defaultValue="#3b82f6"
/>

Usage

Use when

  • Theme and brand customisation
  • Any colour the user must pick freely
  • Design tool inputs

Avoid when

  • A fixed palette (use RadioGroup with swatches)
  • Showing a colour without editing it (use a tinted Badge)
  • Status colour that should come from a token

Implementation notes

  • Label says what the colour is for
  • Use helperText for constraints, such as contrast rules
  • Offer presets next to the picker for the common choices
  • Shorthand (#f50) and a missing hash are accepted and normalised to #rrggbb
  • The hex field always shows; a bad hex is flagged inline, never reverted

Installation

pnpm add @usefragments/ui

Import styles once from @usefragments/ui/styles. See the installation guide for framework and theme setup.

Additional packages

  • react-colorful — Optional — renders the visual picker surface; the swatch and hex input work without it.
pnpm add react-colorful

Anatomy

Import ColorPicker once, then compose its parts with dot notation.

  • ColorPicker.preload

Examples

With Helper Text

Supporting line says where the colour will be used.

<ColorPicker
  label="Primary Color"
  defaultValue="#10b981"
  helperText="This color will be used for buttons and links"
/>

Controlled

The parent owns the value and sees every change.

const [color, setColor] = React.useState('#10b981');

<ColorPicker label="Accent" value={color} onValueChange={setColor} />

Multiple Pickers

A stacked set reads as one palette.

<div style={{ display: 'flex', flexDirection: 'column', gap: '16px', maxWidth: '280px' }}>
  <ColorPicker label="Primary" defaultValue="#3b82f6" />
  <ColorPicker label="Secondary" defaultValue="#64748b" />
</div>

Sizes

Three swatch sizes: sm, md, lg.

<div style={{ display: 'flex', flexDirection: 'column', gap: '16px', maxWidth: '280px' }}>
  <ColorPicker label="Small" defaultValue="#3b82f6" size="sm" />
  <ColorPicker label="Medium (default)" defaultValue="#3b82f6" size="md" />
</div>

Invalid

Red border on the hex field, and the reason below it.

<ColorPicker
  label="Brand Color"
  defaultValue="#7c3aed"
  invalid
  errorMessage="This color fails contrast against the page background"
/>

Read Only

The value is shown and copyable but cannot change.

<ColorPicker label="Brand Color" defaultValue="#3b82f6" readOnly helperText="Set by your organisation" />

Disabled

Swatch will not open and the hex field will not accept typing.

<ColorPicker
  label="Locked Color"
  defaultValue="#64748b"
  helperText="This color cannot be changed"
  disabled
/>

API reference

Component props
Prop
Type
Default
Description
defaultValuestring | undefined#000000Default color for uncontrolled usage
disabledboolean | undefinedfalseDisable the color picker
errorMessagestring | undefinedNot setWords shown under the picker while it is invalid
helperTextstring | undefinedNot setHelper text below the picker (preferred)
invalidboolean | undefinedfalseMarks the value invalid: danger edges plus the error message
labelstring | undefinedNot setLabel text above the picker
onValueChange((color: string) => void) | undefinedNot setCalled with the new #rrggbb value whenever it changes
readOnlyboolean | undefinedfalseShows the value without letting it change
sizeColorPickerSize | undefinedsmmdmdControl size
valuestring | undefinedNot setControlled color value in hex format (#RRGGBB)

Accessibility

  • The group is labelled by the label; the swatch and hex field carry their own names
  • Helper and error text are linked with aria-describedby
  • The picker popup is reachable from the keyboard
  • Users can type a hex instead of dragging
  • An invalid value shows an icon and words, not colour alone
  • InputsiblingColorPicker is a specialized input for colors
  • RadioGroupalternativeUse RadioGroup for predefined color choices
  • FieldparentColorPicker uses Field internally for structure

Next steps