Color picker

Edits one CSS color through a saturation plane, channel sliders, a harmony wheel or swatches, inline or in a popup.

<tp-color-picker>
Color picker
Default density Compact density Restart from the initial state Show the copyable source

Usage

The value is a CSS Color 4 string serialized in the active format, while the widget keeps a floating-point color internally, so switching formats or dragging never accumulates rounding. Give the picker an inline size; its surfaces fill the width they get.

The default composition is the saturation/brightness area with hue and alpha Sliders, a format Select and numeric fields.

picker="popup" puts the panel in a Popover opened from a Color input swatch. The popup header compares the original and current colors, copies the value and offers the eyedropper; pressing the original restores it.

Popup in a field
Default density Compact density Restart from the initial state Show the copyable source

formatSelect, preview and eyedropper hide their header items as they hide the inline ones. Author slot="trigger" content to replace the default trigger. open / defaultOpen, setOpen(open, reason?) and close() forward to the Popover, which remains the state owner; its tp-open-change and tp-open-change-complete events are re-dispatched from the widget with the Popover’s reasons. Opening moves focus to the first dimension of the active view and closing returns it to the trigger.

A Color input in the trigger slot opens the popup instead of the browser’s picker and always shows the picker’s color. An inline one shows the color as a row with its text: a color typed there becomes the picker’s value.

Color input trigger
Default density Compact density Restart from the initial state Show the copyable source

In a form

With a name, the picker submits its string through the surrounding form and takes part in reset. Recent colors are application state: record each commit and hand the last few back through recent, and they appear in the popup’s swatch strip.

Popup in a form
Default density Compact density Restart from the initial state Show the copyable source
Save Reset
Pick a color, then save.

The widget is form-associated: name submits the value string, uncontrolled reset restores the default (form-reset), required reports a missing value with strings.valueMissing, and restoration updates uncontrolled state. Place the picker inside tp-field for a label, description and error; the Field names the root group and label activation focuses the first dimension.

Formats

format never follows the notation you supply: any CSS color goes in, and value reads back in the active format. formats limits the format Select; alpha="false" drops alpha and keeps every published value opaque.

Limited formats, no alpha
Default density Compact density Restart from the initial state Show the copyable source

The widget accepts every CSS Color 4 absolute notation (hex with 3, 4, 6 or 8 digits, legacy and modern rgb() / hsl(), hwb(), lab(), lch(), oklab(), oklch(), color() in the sRGB, linear sRGB and XYZ spaces, named colors, transparent, none) plus the non-CSS hsv() and device-cmyk() notations. Whatever notation an owner supplies, value reads back as the canonical serialization of the active format: modern space-separated syntax, lowercase, alpha appended as / a only when it is below 1 after rounding to two decimals.

Changing the format proposes tp-format-change (cancelable); once accepted, the widget publishes the re-serialized value through a non-cancelable tp-value-change followed by tp-value-commit with metadata.formatChange: true. The color itself is invariant across formats.

The read-only color property exposes the floating-point { space, coords, alpha } record; hsv() and device-cmyk() strings are not parsable by the browser, so consumers that need CSS read color or pick another format.

Typing a hex value without alpha digits keeps the current alpha, text that does not parse reverts to the current color, and a hue of 360 stays 360. A drag through black, white or gray keeps the last chromatic hue and saturation.

Views

views lists the available views; more than one renders a tab strip. Channel sliders edit each channel of the format, the wheel derives harmony colors from a base, and the triangle is the classic hue ring around an HSV triangle.

Channel sliders
Default density Compact density Restart from the initial state Show the copyable source
Harmony wheel and triangle
Default density Compact density Restart from the initial state Show the copyable source

default-harmony sets the starting rule; a harmony attribute makes the rule controlled. The ring around the wheel copies each harmony color on press.

Derived handles follow the base; under custom every handle is its own hue and saturation pair, seeded from the previous rule so the layout does not jump.

harmonyColors lists the base color first and then the derived ones, in the active format, so the palette can drive the rest of your interface.

Reading the palette
Default density Compact density Restart from the initial state Show the copyable source

Swatches and schemes

Saved swatches are a property, set from data; recent colors are application-owned too, since the widget keeps no history. The schemes view generates tints, shades and related strips from the current color.

Brand swatches
Default density Compact density Restart from the initial state Show the copyable source

swatches accepts strings or { label, colors } groups.

Without consumer data the widget generates tints, shades, tones, analogous, complementary, triad and tetrad rows in OKLab/OKLCH from the current color, every entry gamut-mapped to sRGB; the rows stay pinned to the color they were generated from until the “Generate schemes” wand is pressed, so strips never move under a press. Supply schemes ({ label, palettes: [{ label, colors }] }[]) to replace generation with templates chosen through the Template Select. Pressing a scheme or saved swatch proposes that color (item-press, or keyboard when selected from the keyboard); pressing the selected swatch again proposes nothing.

Listening to changes

Drags publish tp-value-change while moving and one tp-value-commit on release, so expensive work belongs on the commit. Cancel a tp-value-change to reject a proposal.

Commit events
Default density Compact density Restart from the initial state Show the copyable source
Saved: #facc15

metadata carries the floating-point color of the proposal and, when known, the edited channel, the surface (area, wheel, triangle, slider, field, swatch, scheme, eyedropper, compare) and formatChange. Only the widget’s own events cross its boundary; the Sliders, Inputs, Selects, Tabs, Toggle Groups and Popover inside never leak their lane events.

Escape during a drag restores the pre-press value (escape-key) and pointer cancellation restores it as well (pointer); neither commits. A capture lost before the release, or a move that reports no pressed button, ends the drag where the pointer last was and commits it (drag), so the last release always settles. Keyboard steps, wheel scrubbing (opt-in through allowWheelScrub), swatches, the eyedropper, hex Enter and blur, and setValue() commit immediately (a paste counts as typing, so it commits on Enter or blur). Numeric fields commit when the Number field commits (Enter or blur).

Controlled, with limits

Set value to own the color: each proposal arrives in onValueChange, and only the values you write back are shown. event.detail.metadata.color carries the proposal as floating-point coordinates, so you can check it before accepting. This one refuses colors too light for white button text; drag toward white and the handle stops.

Controlled owner
Default density Compact density Restart from the initial state Show the copyable source
Start free trial

A refused proposal leaves the value, every surface, the fields and the form state unchanged.

Supply value for a controlled picker or defaultValue for an uncontrolled one; the mode stays fixed for the element’s lifetime. The same rule applies to the format, view, harmony and open lanes.

Trimming the panel

The controls around the color surface can each be turned off. fields="false" removes the row of value boxes, format-select="false" the format Select, preview="false" the color swatch and eyedropper="false" the screen picker, leaving a surface for quick, approximate choices.

Surface only, and fields without a format choice
Default density Compact density Restart from the initial state Show the copyable source

The fields row (fields), format Select (formatSelect), preview swatch (preview) and eyedropper (eyedropper, rendered only where the platform EyeDropper API exists) are independent toggles.

Sizes and states

Small and read-only
Default density Compact density Restart from the initial state Show the copyable source

readonly keeps focus and form submission but blocks every edit; disabled removes both.

size (sm, default, lg) scales the area, tracks, thumbs and swatches; shape (square, round) shapes the preview and swatches.

Right-to-left

Under dir="rtl" the area and the Sliders mirror with the writing direction, so dragging toward the end edge still raises the value. Angular surfaces, the wheel and the hue ring, keep their geometry.

Right-to-left
Default density Compact density Restart from the initial state Show the copyable source

Keyboard and pointer

Every editable dimension is a hidden native range input inside its thumb or handle.

Surface / controlKeysArea, triangleLeft/Right saturation, Up/Down brightness on either input; Page Up/Down, Home, End act on the focused dimensionHue ring, wheel hueLeft/Right/Up/Down step the hue; it wraps past 0 and 360Wheel saturationarrows step saturation; Home/End reach the boundsHue and alpha Slidersthe Slider keyboard model; the hue Slider wraps past 0 and 360 instead of clampingChannel Sliders / fieldsSlider and Number field models (arrows, Page keys, Home/End, Shift/Control/Meta for the large step, Alt for the small one)Swatches, schemesToggle Group roving focus; Space/Enter selectPopupEnter/Space on the trigger opens; Escape closes and returns focus; the header’s Select, original swatch, Copy button and eyedropper are ordinary stops ahead of the surface

On the surfaces and Sliders arrow steps use the channel step; Shift, Control or Command and the Page keys use the large step, Alt the small step. The numeric fields follow the Number field model with their last displayed digit as the step (0.001 for the OK channels, 0.1 for Lab and the OKLCH hue, 1 elsewhere), so every value the fields show is valid; Shift still uses the channel’s large step. Horizontal arrows follow the writing direction on the area and Sliders; angular axes (wheel, ring) do not flip. Pointer presses capture the pointer, coalesce movement to one proposal per frame and release once. A press inside a handle (the area thumb, a wheel handle, the ring or triangle thumb, a Slider thumb) keeps the pointer’s offset from the handle’s center, so the handle moves with the pointer instead of jumping under it; a press elsewhere moves the handle to the press point. Under a harmony rule the derived wheel handles follow the base, so a press on one of them moves nothing, and where a derived handle shares or overlaps the base’s position the base still takes the press. Shift snaps coarsely and Alt moves finely on Sliders.

Constituents and accessibility

Every dimension exposes the slider role with an accessible name of the form ${label}: ${name} (Hue, Saturation, Brightness, Lightness, Red, …, Alpha) and value text in display precision with its unit (242°, 66%, 0.628). The area and triangle inputs sit in a group named “Saturation and brightness”, the wheel in “Hue and saturation”; custom harmony handles expose “Harmony color N: Hue/Saturation”. The root is a group named by label (or aria-label). Tab order per view: tabs, surface inputs, eyedropper, hue, alpha, format Select, fields, alpha field, then one roving stop per swatch group; in the popup the header (format Select, original swatch, Copy button, eyedropper) precedes the surface. The original swatch is a Button named “Restore the original color” plus the original serialization; the current swatch is decorative; the Copy button announces its result. Harmony palette segments are Copy buttons named “Copy color” plus their serialization, grouped as “Harmony palette”, in the tab order right after the wheel. strings overrides every name (hue, alpha, eyedropper, compare, original, copy, palette, savedColors, viewWheel, formatOklch, harmonyTriad, schemeTints, …) for localization; locale formats the numeric fields.

API Reference

Every element also accepts motion-policy.

Attributes

AttributePropertyTypeDefaultDescriptiondefault-valuedefaultValuestring | undefined—Starting color of an uncontrolled picker, in any CSS color notation; form reset returns to it.formatformatColorFormat—The active format the value is serialized in; setting it makes the format choice controlled. Any CSS color goes in, and value reads back in this format.default-formatdefaultFormatColorFormat | undefined—Starting format of an uncontrolled format choice; the value is serialized in it.formatsformatsreadonly ColorFormat[]COLOR_FORMATSThe formats the format Select offers, in order (a space-separated list as an attribute).alphaalphabooleantrueWhether the color carries alpha: an alpha Slider and field, and transparency in the value. Turn it off to keep every published value opaque.pickerpickerColorPickerPicker'inline'Renders the panel in place, or inside a Popover opened from a swatch trigger with a header that compares, copies and picks from the screen.viewsviewsreadonly ColorPickerView[]['area']The views on offer, in tab order (a space-separated list as an attribute); more than one adds a tab strip.viewviewColorPickerView—The active view among views; setting it makes the view choice controlled.default-viewdefaultViewColorPickerView | undefined—Starting view of an uncontrolled view choice; without it the first of views opens.fieldsfieldsbooleantrueShows the row of numeric fields for the channels of the active format.format-selectformatSelectbooleantrueShows the Select that switches the active format.previewpreviewbooleantrueShows the swatch of the current color.eyedroppereyedropperbooleantrueOffers the screen color picker where the browser supports it.sizesizeColorPickerSize'default'Scales the surfaces, tracks, thumbs and swatches together.shapeshapeColorPickerShape'square'Shapes the preview and the swatches as squares or circles.harmonyharmonyHarmonyRule—The harmony rule that derives extra handles on the wheel; setting it makes the rule controlled, so the Harmony Select only proposes.default-harmonydefaultHarmonyHarmonyRule | undefined—Starting rule of an uncontrolled harmony choice on the wheel. Prefer it in markup: a harmony attribute makes the rule controlled.allow-wheel-scruballowWheelScrubbooleanfalseLets the mouse wheel step the hovered surface or Slider; off so that scrolling the page never edits the color.labellabelstring''Accessible name of the picker's group and the prefix of every dimension's name; a surrounding Field supplies it otherwise.localelocalestring''Locale used to format the numbers in the fields.openopenboolean—Popup open state; the composed Popover remains the state owner.default-opendefaultOpenbooleanfalseOpens the popup on first render, for an uncontrolled popup picker.

Properties

PropertyTypeDefaultDescriptionswatchesreadonly ColorSwatchInput[][]Saved colors for the swatches view: a flat list of CSS colors or labeled groups of them.recentreadonly string[][]Recent colors supplied by the application; the widget keeps no history of its own.schemesreadonly ColorScheme[][]Palette templates for the schemes view, chosen through a template Select; when empty, the view generates tints, shades and related strips from the current color.stringsPartial<ColorPickerStrings>{}Replaces built-in names and messages (channel names, view tabs, harmony rules, scheme rows) for localization.onValueChangeColorPickerValueChangeCallback | undefined—Called synchronously with each tp-value-change proposal, before listeners; a controlled owner writes value back here to accept it.onValueCommittedColorPickerValueCommitCallback | undefined—Called with each settled value, once per drag, keystroke, swatch press or field commit.colorread-onlyColorValue | null—The internal floating-point color in the working space of the format, or null when empty.controlledread-onlyboolean—Whether the value is owned by the application through value.draggingread-onlyboolean—Whether a pointer drag on a surface or Slider is in progress.supportsEyeDropperread-onlyboolean—Whether the browser offers a screen color picker, so pickFromScreen() can work.harmonyColorsread-onlyreadonly string[]—Harmony colors in the active format: the base color first, then the derived handles.

Events

EventTypeDescriptiontp-value-changeTpValueChangeEvent<string>Cancelable color proposal; detail.metadata carries the floating-point color and, when known, the edited channel and surface. A refused proposal changes nothing.tp-value-commitTpValueCommitEvent<string>A settled color: once per drag on release, and at once for keys, swatches, the eyedropper and field commits.tp-format-changeTpValueChangeEvent<ColorFormat>Cancelable format proposal from the format Select.tp-view-changeTpValueChangeEvent<ColorPickerView>Cancelable view proposal from the view tabs.tp-harmony-changeTpValueChangeEvent<HarmonyRule>Cancelable harmony rule proposal from the Harmony Select.tp-open-changeTpOpenChangeEventCancelable proposal to open or close the popup.tp-open-change-completeCustomEvent<{ open: boolean; }>After the popup finishes opening or closing; detail.open.tp-field-valueCustomEvent<{ value: string; previousValue: string; reason: ChangeReason; }>Each committed value, for a surrounding Field's validation state.

Methods

MethodReturnsDescriptionsetValue(value, reason, sourceEvent?)booleanProposes and commits a color; returns whether the proposal was accepted.pickFromScreen()Promise<boolean>Opens the platform eyedropper; resolves true when a color was picked and accepted.setOpen(open, reason, event?)booleanOpens or closes the popup picker through the composed Popover.close()voidCloses the popup picker.

Slots

SlotDescriptionfooterContent below the panel, such as an action row; hidden while empty.triggerReplaces the popup picker's default swatch trigger.

CSS parts

PartDescription::part(color-picker)The root group named by the label, holding the tabs, the active view and the fields.::part(color-picker-alpha-track)The alpha Slider's track over the checkerboard.::part(color-picker-channel)One row of the sliders view: a labeled Slider and its numeric value box.::part(color-picker-compare)The original and current colors side by side; pressing the original restores it.::part(color-picker-compare-current)The comparison's current color segment.::part(color-picker-compare-original)The comparison's original color Button.::part(color-picker-controls)The row under a surface: the eyedropper beside the hue and alpha Sliders.::part(color-picker-copy)The Copy button for the serialized value.::part(color-picker-field)One channel field, or the hex field.::part(color-picker-fields)The row of numeric fields and the format Select.::part(color-picker-footer)The wrapper of the footer slot below the panel.::part(color-picker-format)The Select of the active format.::part(color-picker-harmony)The Select of harmony rules in the wheel view.::part(color-picker-header)The popup's top row: the format Select, the comparison, the Copy button and the eyedropper.::part(color-picker-label)The visible label above the panel.::part(color-picker-palette)The ring around the wheel with one copyable segment per harmony color.::part(color-picker-palette-item)One palette segment's Copy button.::part(color-picker-palette-swatch)The color fill of one palette segment.::part(color-picker-popup)The Popover holding the popup panel.::part(color-picker-preview)The swatch of the current color.::part(color-picker-recent)The strip of recent colors at the bottom of the popup.::part(color-picker-scheme)One strip of related colors.::part(color-picker-scheme-item)One pressable color in a scheme strip.::part(color-picker-schemes)The schemes view: its toolbar and the scheme strips.::part(color-picker-slider-range)A channel Slider's filled range.::part(color-picker-slider-thumb)A channel Slider's thumb.::part(color-picker-slider-track)A channel Slider's track, painted with the channel's range.::part(color-picker-swatch)The color fill inside a swatch or a comparison half.::part(color-picker-swatch-grid)The Toggle group that lays out a swatch grid.::part(color-picker-swatch-item)One pressable swatch in a grid.::part(color-picker-swatches)A grid of saved or recent colors.::part(color-picker-toolbar)The row of choices above the wheel or the schemes: the Harmony or template Select and the generate Button.::part(color-picker-trigger)The swatch Color input that opens the popup picker.

Components, widgets and patterns that use this one.