Beta
Color Picker <mv-color-picker>
Farbfeld, das ein Popover mit Light Dismiss öffnet (oder inline steht): eine Sättigungs-/Helligkeitsfläche, Regler für Farbton und Deckkraft, ein Textfeld, das jede CSS-Farbe annimmt, mit Umschalter HEX/RGB/HSL/OKLCH, die Pipette, Farbmuster und zuletzt verwendete Farben. Jeder Regler sagt einen lesbaren Farbnamen an, und das Element ist ein Formularfeld, dessen Wert eine CSS-Farbe ist.
| Kategorie | Formulare |
|---|---|
| Typ | Web Component (<mv-color-picker>) |
| Status | Beta |
| Keywords | color, picker, oklch, hex, hsl, eyedropper, swatches, popover, form-associated, editor |
When to use
- Users choose an arbitrary color in a theme builder, design tool or brand settings page
- A form field should submit a CSS color, with swatches and recent colors for quick reuse
- Colors are pasted or typed in any CSS syntax and edited in HEX, RGB, HSL or OKLCH with opacity
Avoid when
- Shoppers choose a product color among a few fixed variants → use Swatch instead
- The value is a multi-stop gradient rather than a single color → use Gradient Editor instead
Installation
node scripts/add.mjs color-picker --out ./src/marvelousKI-Agent mit dem MCP-Server von Marvelous UI: install_components({ slugs: ["color-picker"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).
Kopierte Dateien (inklusive Abhängigkeiten): tokens/tokens.css, core/base.css, core/canvas.js, core/dom.js, core/element.js, core/focus.js, core/form.js, core/position.js, components/color-picker/color-picker.js, components/color-picker/color-picker.css.
Verwendung
Referenz-Markup zum Starten und Anpassen mit Attributen, data-* und CSS-Variablen:
<div id="cp-demo">
<style>
#cp-demo { display: flex; flex-wrap: wrap; gap: 1.5rem; align-items: flex-start; justify-content: center; width: 100%; }
#cp-demo .cpd-col { display: grid; gap: 1rem; width: 17rem; }
#cp-demo .cpd-preview { display: grid; place-items: center; height: 9.5rem; border: 1px solid var(--mv-border); border-radius: var(--mv-radius-xl); background: var(--cpd-surface, var(--mv-bg)); transition: background var(--mv-duration-fast); }
#cp-demo .cpd-ticket { display: grid; gap: .2rem; min-width: 11rem; padding: .9rem 1rem; border-radius: .9rem; background: var(--cpd-brand); color: var(--cpd-ink); font: 600 .95rem/1.25 var(--mv-font-sans); box-shadow: 0 16px 32px -18px var(--cpd-brand); }
#cp-demo .cpd-ticket small { font: 500 .65rem/1.4 var(--mv-font-mono); opacity: .8; }
#cp-demo .cpd-form { display: grid; gap: .6rem; padding: .9rem; border: 1px solid var(--mv-border); border-radius: var(--mv-radius-lg); background: var(--mv-surface); }
#cp-demo .cpd-head { margin: 0; font: 600 .7rem var(--mv-font-sans); letter-spacing: .06em; text-transform: uppercase; color: var(--mv-fg-muted); }
#cp-demo .cpd-row { display: grid; grid-template-columns: 4.75rem 1fr; align-items: center; gap: .5rem; font-size: .8rem; color: var(--mv-fg-muted); }
#cp-demo .cpd-row mv-color-picker { width: 100%; }
#cp-demo .cpd-marks { display: flex; align-items: center; gap: .5rem; font-size: .8rem; color: var(--mv-fg-muted); }
</style>
<div class="cpd-col">
<div class="cpd-preview" id="cp-demo-preview">
<div class="cpd-ticket">Summer Pass · $49<small id="cp-demo-out"></small></div>
</div>
<form class="cpd-form" aria-label="Theme" onsubmit="return false">
<p class="cpd-head">Theme</p>
<div class="cpd-row"><label for="cp-demo-brand">Brand</label>
<mv-color-picker id="cp-demo-brand" name="brand" value="#7C3AED"></mv-color-picker>
</div>
<div class="cpd-row"><label for="cp-demo-surface">Surface</label>
<mv-color-picker id="cp-demo-surface" name="surface" format="oklch" value="oklch(94% 0.03 300 / 0.8)"></mv-color-picker>
</div>
<div class="cpd-row"><label for="cp-demo-ink">Text</label>
<mv-color-picker id="cp-demo-ink" name="ink" value="rgb(255 255 255)" opaque swatches="#FFFFFF, #F8FAFC, #FDE68A, #1E1B4B, #0F172A"></mv-color-picker>
</div>
<div class="cpd-marks">Tags
<mv-color-picker data-variant="swatch" label="Tag Sale" value="#F97316" opaque></mv-color-picker>
<mv-color-picker data-variant="swatch" label="Tag New" value="#14B8A6" opaque></mv-color-picker>
<mv-color-picker data-variant="swatch" label="Tag Sold out" value="#64748B" opaque></mv-color-picker>
</div>
</form>
</div>
<mv-color-picker inline label="Accent" value="#EC4899" no-recent></mv-color-picker>
</div>
<script type="module">
const $ = (id) => document.getElementById(`cp-demo-${id}`);
const apply = () => {
const p = $("preview");
p.style.setProperty("--cpd-brand", $("brand").value);
p.style.setProperty("--cpd-surface", $("surface").value);
p.style.setProperty("--cpd-ink", $("ink").value);
$("out").textContent = $("brand").value;
};
document.getElementById("cp-demo").addEventListener("mv-input", apply);
customElements.whenDefined("mv-color-picker").then(() => requestAnimationFrame(apply));
</script>API
Attributes
| Name | Typ | Default | Description |
|---|---|---|---|
value | string | #000000 | Initial CSS color (hex, rgb(), hsl(), hwb(), oklch(), oklab(), name, var()…). Restored on form reset. |
format | hex | rgb | hsl | oklch | inferred from value | Output and field format; the user can switch it in the panel. |
label | string | Color | Accessible name of the well and the panel (falls back to an associated <label>). |
swatches | string | Comma-separated colors for the swatch row; an empty string hides it. | |
inline | boolean | Panel rendered in place, with no well or popover; mv-change fires at the end of each gesture. | |
opaque | boolean | Hides opacity (alpha is always 1). | |
no-recent | boolean | Neither reads nor saves recent colors (shared localStorage). | |
placement | string | bottom-start | Popover placement, flipped and shifted to stay on screen. |
name / disabled / readonly | Standard form behavior; readonly still opens the panel to read and copy the value. | ||
data-variant | swatch | Round swatch only, no text. |
Properties
| Name | Typ | Description |
|---|---|---|
value | string | CSS color in the current format (an oklch value is kept exactly, even outside the sRGB gamut). Setting it does not fire events. |
rgba | { r, g, b, a } | Channels from 0 to 1. |
hex | string | “#RRGGBB”, or “#RRGGBBAA” when translucent. |
mode | string | Current format (read and write). |
isOpen | boolean | Whether the popover is open. |
strings | object | Overrides for every visible and announced label, color names included (i18n). |
Methods
| Name | Description |
|---|---|
show() / hide() | Opens or closes the popover; closing with a new color fires mv-change. |
parseColor(str, el?) / formatColor(rgba, mode, lch?) / mixColors(a, b, t) / colorName(rgba) | Module exports: parsing (null when not a color), formatting, sRGB mix, readable name. HSV, HSL and OKLCH conversions are exported too. |
Events
| Name | Description |
|---|---|
mv-input | Live change (drag, keys, typing, swatch). detail: { value, hex, rgba }. |
mv-change | Popover closed with a new color, or end of a gesture when inline. The color joins the recent ones. |
mv-open / mv-close | Popover opened and closed. |
CSS classes
| Name | Description |
|---|---|
mv-color-picker-trigger / -chip / -panel / -area / -hue / -alpha / -compare / -fields / -format / -input / -swatch | Generated parts. |
CSS variables
| Name | Default | Description |
|---|---|---|
--mv-color-picker-width | 8.5rem | Well width. |
--mv-color-picker-panel-width | 17.5rem | Panel width. |
--mv-color-picker-area-height | 9.5rem | Height of the saturation/brightness area. |
--mv-color-picker-columns | 10 | Swatches per row. |
Accessibility
The well is a button (aria-haspopup=dialog, aria-expanded) whose name holds the label, a readable color name and the value. The popover is a named dialog that closes on outside click, Escape, Enter or when focus leaves it, and focus returns to the well. The 2D area is a slider (aria-valuetext “Saturation 80%, brightness 60%, dark violet”) moved with the arrow keys (Shift ×10, Page Up/Down for brightness, Home/End for saturation). Hue and opacity are sliders that also name the color. The format is a native select, the text field accepts any CSS color and its arrow keys nudge the number under the caret; invalid text sets aria-invalid. Swatch groups have one tab stop each and arrow-key navigation, with aria-pressed on the current color. Forced colors keep the color surfaces and switch outlines, thumbs and focus to system colors.