Skip to content

API Reference

The <color-input> element accepts these HTML attributes:

The value attribute sets the color using standard CSS color syntax.

<color-input value="oklch(70% 20% 240)"></color-input>
Value
oklch(70% 20% 240)
Color Space
oklch
Gamut
Contrast Color
View Code
<color-input value="oklch(70% 20% 240)"></color-input>

Accepted inputs include common CSS formats such as:

  • hex colors
  • rgb() / hsl() / hwb()
  • lab() / lch() / oklab() / oklch()
  • color(display-p3 ...), color(rec2020 ...), color(prophoto-rgb ...), and similar color(...) forms
  • CSS named colors such as rebeccapurple

Without an explicit colorspace or initial-colorspace, the editing space is inferred from the string’s notation, since the notation you wrote is the one you probably want to keep editing in. #3b82f6 opens in hex, hsl(240 80% 60%) in hsl, color(display-p3 ...) in display-p3.

Named colors are the exception. rebeccapurple expresses no format preference, so it opens in oklch rather than srgb, which puts the wide-gamut controls in front of you by default.

A parseable color whose space has no controls in the picker also falls back to oklch.

The colorspace attribute controls which editing space the UI uses.

<color-input
value="color(display-p3 0.3 0.7 0.95)"
colorspace="oklch"
></color-input>

When this changes, the component converts the current color into the requested space and rebuilds the controls to match.

Use initial-colorspace when you want the picker to open in a specific editing space without rewriting the incoming value string on first render.

<color-input value="#000" initial-colorspace="hsl"></color-input>

If colorspace is also present, colorspace wins.

Start from a hex token but open the picker with HSL controls for hue and saturation editing.

Value
#3b82f6
Color Space
oklch
Gamut
Contrast Color
View Code
<color-input value="#3b82f6" initial-colorspace="hsl"></color-input>

The theme attribute controls the visual appearance:

  • auto (default) - Respects user’s system preference
  • light - Always uses light theme
  • dark - Always uses dark theme
Value
oklch(65% 20% 280)
Color Space
oklch
Gamut
Contrast Color
View Code
<color-input value="oklch(65% 20% 280)"></color-input>

The no-alpha attribute hides the alpha channel control from the color picker. When present, users cannot modify the alpha/opacity value through the UI, though the alpha value is still preserved in the color.

<color-input value="red" no-alpha></color-input>
Value
red
Color Space
oklch
Gamut
Contrast Color
View Code
<color-input value="red" no-alpha></color-input>

There are two editable text fields for the color string: the inline field next to the trigger, and the field in the picker’s preview footer. Both accept anything the CSS Color Level 4 parser understands and keep the sliders, area picker, preview, and computed properties in sync as you type.

  • Validation runs on every keystroke, and a valid value commits immediately. The sliders rebuild when the entered syntax implies a different colorspace.
  • Leaving a field reverts any uncommitted text — an unparseable entry, or one that normalized to a different string — back to the current value.
  • Pasted text is normalized before parsing: surrounding whitespace and zero-width characters are dropped, a wrapping CSS declaration is unwrapped (color: red;red), and bare hex digits gain a leading # (ff6600#ff6600).
  • When parsing fails the host gains a data-error attribute, the textbox sets aria-invalid="true", and the inline error message becomes visible.
  • Restyle the field with ::part(input) and target invalid states with [data-error].
<color-input value="#9333ea"></color-input>

The value shown over the color swatch is editable too, which makes it a one-click paste target while the picker is open.

  • Focusing it selects the whole value, so a paste replaces it and a manual copy needs no dragging.
  • Invalid entries mark the field aria-invalid="true" and draw an outline in the swatch’s contrast color. They don’t set the host-level data-error state.
  • Enter commits and leaves the field. Escape abandons the edit — including any color already committed live — and keeps the picker open; a second Escape closes it.
  • Restyle it with ::part(output).

Hover or focus the preview area to reveal a copy button. Activating it copies the current color string with navigator.clipboard.writeText() and shows a “Copied!” status message inside the panel. No configuration is required—the control works for every supported color space, including hex.

Hover or focus the preview area to reveal an eye dropper button to the left of the copy button. Activating it opens the native browser eye dropper, allowing you to pick colors from anywhere on your screen.

The browser returns an sRGB hex value, which the component then converts into the current editing space before updating value.

The <color-input> element exposes these properties:

value - Current color as a CSS string

const picker = document.querySelector("color-input");
console.log(picker.value); // "oklch(70% 20% 240)"
picker.value = "oklch(80% 15% 180)";

colorspace - Current color space

console.log(picker.colorspace); // "oklch"
picker.colorspace = "hsl";

Supported values:

  • hex
  • srgb
  • srgb-linear
  • hsl
  • hwb
  • lab
  • lch
  • oklab
  • oklch
  • display-p3
  • a98-rgb
  • rec2020
  • prophoto
  • xyz
  • xyz-d50
  • xyz-d65

initialColorspace - Preferred startup color space

console.log(picker.initialColorspace); // null | "hsl" | "oklch" | ...
picker.initialColorspace = "hsl";

theme - Visual theme

console.log(picker.theme); // "auto"
picker.theme = "dark"; // "auto", "light", or "dark"

noAlpha - Controls alpha channel visibility

console.log(picker.noAlpha); // false
picker.noAlpha = true; // Hides alpha controls
picker.noAlpha = false; // Shows alpha controls

gamut - Detected gamut (smallest gamut that contains the current color)

console.log(picker.gamut); // "srgb" | "p3" | "rec2020" | "xyz"

contrastColor - Recommended text color for contrast

console.log(picker.contrastColor); // "white" or "black"

Opens the picker popover programmatically:

const picker = document.querySelector("color-input");
picker.show();

show() can also accept a custom anchor element:

picker.show(document.querySelector("#anchor"));

Alias for show() retained for compatibility with earlier versions:

picker.showPicker();

Closes the picker popover:

picker.close();

Sets a custom anchor element for popover positioning:

const customAnchor = document.querySelector("#my-anchor");
picker.setAnchor(customAnchor);

By default, the popover positions relative to the internal trigger button. When possible, the component can use native CSS anchor positioning; otherwise it falls back to manual viewport-aware placement.

<color-input> listens for Popover command events so you can wire it up with declarative popovertarget controls or custom command dispatchers.

  • Buttons with popovertarget automatically send show, hide, or toggle commands that the element consumes.
  • The component accepts either the short (show, hide, toggle) or Popover-specific (show-popover, hide-popover, toggle-popover) command strings.
  • When a command originates from an invoker element, that invoker becomes the new popover anchor via setAnchor().
<button popovertarget="picker" popovertargetaction="toggle">
Toggle color picker
</button>
<color-input id="picker"></color-input>

You can also trigger commands manually:

const cmd = new Event("command", { bubbles: true });
Object.assign(cmd, { command: "show" });
picker.dispatchEvent(cmd);

The <color-input> element dispatches three custom events:

Fired when the color value changes. The event detail contains:

interface ChangeDetail {
value: string; // CSS color string, e.g., "oklch(70% 20% 240)"
colorspace: string; // Current color space, e.g., "oklch"
gamut: string; // Detected gamut: "srgb", "p3", "rec2020", or "xyz"
}
picker.addEventListener("change", (event) => {
const { value, colorspace, gamut } = event.detail;
console.log(`New color: ${value}`);
console.log(`Color space: ${colorspace}`);
console.log(`Gamut: ${gamut}`);
});

Fired when the picker popover opens:

picker.addEventListener("open", () => {
console.log("Picker opened");
});

Fired when the picker popover closes:

picker.addEventListener("close", () => {
console.log("Picker closed");
});

The popover includes a two-dimensional color area. Its model changes with the active colorspace:

  • srgb and hex use an OKHSV-based plane
  • hsl uses saturation × lightness
  • oklch, lch, and wide-gamut RGB-like spaces use a chroma × lightness plane
  • oklab and lab use a centered a × b plane
  • hwb uses whiteness × blackness

Click or drag anywhere inside the area to update the current color. The thumb tracks the current position and the serialized value updates as you move.

Focus the area and use the arrow keys:

  • ←/→ — adjust the X-axis channel in fine steps
  • ↑/↓ — adjust the Y-axis channel in fine steps

Target the area container with ::part(area):

color-input::part(area) {
border-radius: 12px;
aspect-ratio: 16 / 9;
}

For spaces with explicit gamut behavior, the area can render boundary overlays and stretch the mapping so the useful region of the gamut occupies more of the canvas.

The <color-input> element exposes several CSS parts for styling with the ::part() selector:

  • trigger - The button that opens the picker
  • chip - Color swatch inside the trigger button
  • input - Inline text field for direct color entry
  • error - Text with color parsing error message
  • panel - Popover container
  • output - Editable CSS color string in the preview footer
  • gamut - Gamut badge (srgb/p3/rec2020/xyz)
  • controls - Container for channel sliders and inputs
  • area - Container for area picker

The preview area also exposes two useful pieces of information:

  • a gamut indicator showing the smallest tracked gamut containing the current color
  • contrast ratios against white and black

These are especially useful when the picker is part of a design tool, theming UI, or token editor.

While the picker is open, the color string is mirrored into a polite live region so changes made through the sliders, area picker, or eye dropper are announced. Only the settled value is announced — a slider drag doesn’t produce an announcement per frame — and typing into either text field is skipped, since the field already echoes what you entered.