v2.6.0

<bmx-color-picker>

A colour field, or a colour panel in the page. Saturation and brightness on a square, hue and opacity on tracks, the value typed in hex, RGB, HSL or OKLCH, the page's brand colours and design tokens as swatches, recent colours, the screen's own eyedropper where the browser has one, and a live WCAG contrast check against a background - with a button that finds the nearest colour of the same hue that passes.

28 properties · 4 events · 5 methods · 21 parts

Example

Choose a colour.

Heading text
Show markup
<div class="row" style="display: flex; gap: 24px; flex-wrap: wrap; align-items: flex-start">
  <div style="display: grid; gap: 12px">
    <bmx-color-picker id="ex-cp-brand" label="Brand colour" name="brand" value="#1a73e8" clearable description="Any CSS colour can be typed: a name, hex, rgb(), hsl() or oklch()."></bmx-color-picker>
    <p class="note" id="ex-cp-out" role="status" style="margin: 0">Choose a colour.</p>
    <div id="ex-cp-preview" style="display: grid; place-items: center; inline-size: 14rem; block-size: 4rem; border-radius: 12px; background: #1a73e8; color: #ffffff; font-weight: 600">Heading text</div>
  </div>
  <bmx-color-picker id="ex-cp-text" label="Heading text colour" mode="inline" alpha value="#8ab4f8" contrast-with="#1a73e8" description="Checked against the brand colour as text on it (WCAG AA, 4.5:1)."></bmx-color-picker>
</div>

<script type="module">
  await customElements.whenDefined('bmx-color-picker');
  const brand = document.getElementById('ex-cp-brand');
  const text = document.getElementById('ex-cp-text');
  const preview = document.getElementById('ex-cp-preview');
  const out = document.getElementById('ex-cp-out');
  const swatches = [
    { value: '#1a73e8', label: 'Blue 600', group: 'Brand' },
    { value: '#174ea6', label: 'Blue 800', group: 'Brand' },
    { value: '#e37400', label: 'Orange 700', group: 'Brand' },
    '#202124', '#5f6368', '#dadce0', '#ffffff', '#d93025', '#f9ab00', '#188038', '#12b5cb', '#9334e6',
  ];
  brand.swatches = swatches;
  text.swatches = swatches;
  brand.addEventListener('bmxChange', async e => {
    const color = e.detail.color;
    out.textContent = color ? `${color.hex} · ${color.rgb} · ${color.oklch} (${color.description})` : 'No colour.';
    preview.style.background = e.detail.value || 'transparent';
    text.contrastWith = e.detail.value || '#ffffff';
  });
  text.addEventListener('bmxInput', e => (preview.style.color = e.detail.value || 'inherit'));
  preview.style.color = text.value;
  // Recent colours are the page's to keep: here, for this visit only.
  brand.addEventListener('bmxRecentChange', e => (text.recent = e.detail.recent));
</script>
<bmx-color-picker label="Brand colour" name="brand" value="#1a73e8"
  swatches='["#1a73e8", "#188038", "#d93025", "var(--brand-accent)"]'
  contrast-with="#ffffff"></bmx-color-picker>

value is always written in format (hex, rgb, hsl or oklch), whatever was typed: "red", hsl(0 100% 50%) and #f00 all become #ff0000 in hex. The form receives the same text. With alpha the value carries opacity (#1a73e880, rgba(...)); without it every colour is opaque.

A swatch may name a CSS custom property (var(--brand-500) or --brand-500); it is read from the page, so the swatches follow the theme, and bmxChange says which token was chosen.

Recent colours are the page's to keep: a colour is added when the panel closes (or, inline, when focus leaves) on a new value, and bmxRecentChange hands over the list. Nothing is stored.

Keyboard: on the square, arrows move saturation (left, right) and brightness (up, down), Shift ten at a time, Page Up and Page Down brightness by ten, Home and End saturation to its ends; the tracks are sliders. In the text box Enter takes what was typed, Alt+Down opens the panel, Escape puts the value back. Swatches are one tab stop, arrows between them. Escape closes the panel and returns focus to the field.

Properties

PropertyAttributeTypeDefaultDescription
alpha alpha boolean false Allow opacity: an opacity track, and a value that carries it.
clearable clearable boolean false Show a button that clears the colour.
contrastLevel contrast-level BmxContrastLevel 'AA' The WCAG level to meet.
contrastRole contrast-role 'foreground' | 'background' 'foreground' Whether the chosen colour is the foreground against contrast-with, or the background behind it.
contrastUse contrast-use BmxContrastUse 'text' What the colour is used for, which sets the ratio it needs: text (4.5:1 / 7:1), large-text (3:1 / 4.5:1), graphics (3:1).
contrastWith contrast-with string — A colour to check contrast against: any colour, or a custom property. Leave empty for no check.
description description string — Help text below the field.
disabled disabled boolean false Disable the picker.
errorText error-text string — An error supplied by the page.
eyedropper eyedropper boolean true Offer the screen eyedropper, where the browser has one.
format format BmxColorFormat 'hex' How the value is written: hex, rgb, hsl or oklch. Mutable: the reader can switch it in the panel.
formats formats BmxColorFormat[] | string ['hex', 'rgb', 'hsl', 'oklch'] The formats offered in the panel, as an array, JSON or a comma-separated list. Empty hides the switcher.
fullWidth full-width boolean false Stretch to the width of the container.
hideInputs hide-inputs boolean false Leave out the format buttons and channel boxes.
hideLabel hide-label boolean false Hide the label visually while keeping it as the accessible name.
label label string — The field's label.
maxRecent max-recent number 8 The longest the recent list grows. 0 keeps none and hides the list.
mode mode 'popup' | 'inline' 'popup' popup: a field that opens a floating panel. inline: the panel drawn in place.
name name string — The field's name in the form it belongs to.
placeholder placeholder string — The text box's placeholder (popup mode).
placement placement BmxPlacement 'bottom-start' Where the floating panel opens against the field.
readonly readonly boolean false Show the colour without allowing changes.
recent recent string[] | string [] Recent colours, newest first. Mutable: a newly chosen colour is put first.
required required boolean false A colour must be chosen.
strings strings Partial<BmxColorPickerStrings> | string — Words to show instead of the English ones, as an object or JSON.
swatches swatches (BmxColorSwatch | string)[] | string [] Colours offered as swatches: strings or { value, label, group }, as an array, JSON or a comma-separated list.
uppercase uppercase boolean false Hex digits in upper case.
value value string '' The colour, written in format. Empty for none. Two-way.

Events

EventDetailDescription
bmxChange BmxColorChangeDetail Fired when a change is complete: a drag released, a key pressed, a swatch chosen, a value typed.
bmxInput BmxColorChangeDetail Fired continuously while the colour changes - during a drag, on each step.
bmxOpenChange boolean Fired when the floating panel opens or closes.
bmxRecentChange BmxColorRecentDetail Fired when a colour is added to the recent list.

Methods

MethodSignatureDescription
checkContrastWith checkContrastWith(color?: string) => Promise<BmxContrastResult | null> The WCAG contrast of the current colour against another (default: contrast-with), or null.
getColor getColor() => Promise<BmxColorInfo | null> The current colour written every way, or null when there is none.
hide hide() => Promise<void> Close the floating panel.
setFocus setFocus(options?: FocusOptions) => Promise<void> Focus the text box (popup mode) or the square (inline).
show show() => Promise<void> Open the floating panel (popup mode).

Slots

SlotDescription
description Rich help text, in place of the description property.
label Rich label content, in place of the label property.

CSS shadow parts

PartDescription
alpha The opacity track.
area The saturation and brightness square.
area-thumb Its handle.
channel One channel box.
channels The row of channel boxes.
clear The clear button.
contrast The contrast check.
description The help text.
eyedropper The eyedropper button.
field The box around the swatch button and the text (popup mode).
fix The button that fixes the contrast.
formats The format buttons.
hue The hue track.
input The text box (popup mode).
label The label element.
panel The panel: floating in popup mode, in place inline.
preview The before and after chips.
swatch One swatch; also swatch-selected.
swatches A list of swatches (also the recent list).
thumb A track's handle.
trigger The button that opens the panel, showing the colour.

CSS custom properties

PropertyDescription
--bmx-color-picker-area-height The height of the saturation and brightness square.
--bmx-color-picker-height The field's height.
--bmx-color-picker-label-font-size The label's font size.
--bmx-color-picker-panel-background The panel's background.
--bmx-color-picker-panel-shadow The floating panel's shadow.
--bmx-color-picker-panel-width The panel's width.
--bmx-color-picker-radius Corner radius of the field and the panel.
--bmx-color-picker-support-font-size Font size of the description and error message.
--bmx-color-picker-swatch-size The size of a swatch.