Color Picker <mv-color-picker>

外側のクリックで閉じるポップオーバーを開く(またはインラインに置く)カラーウェル:彩度と明度のエリア、色相と不透明度のスライダー、HEX/RGB/HSL/OKLCH の切り替え付きで任意の CSS カラーを受け付ける 1 つのテキストフィールド、スポイト、スウォッチ、最近使った色を備えます。

仕組み

外側のクリックで閉じるポップオーバーを開く(またはインラインに置く)カラーウェル:彩度と明度のエリア、色相と不透明度のスライダー、HEX/RGB/HSL/OKLCH の切り替え付きで任意の CSS カラーを受け付ける 1 つのテキストフィールド、スポイト、スウォッチ、最近使った色を備えます。各スライダーはわかりやすい色名を読み上げさせ、要素自体が CSS カラーを値とするフォームフィールドです。

カテゴリーフォーム
タイプWeb Component(<mv-color-picker>)
ステータス安定版
Keywordscolor, 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

インストール

node scripts/add.mjs color-picker --out ./src/marvelous

Marvelous UI の MCP サーバーを使う AI エージェント:install_components({ slugs: ["color-picker"], target_dir: "<absolute path>/src/marvelous", framework: "react" })。

コピーされるファイル(依存関係を含む):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。

使い方

基本となるマークアップです。ここから属性、data-*、CSS 変数でカスタマイズしてください:

<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 .68rem/1.4 var(--mv-font-mono); }
    #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タイプDefaultDescription
valuestring#000000Initial CSS color (hex, rgb(), hsl(), hwb(), oklch(), oklab(), name, var()…). Restored on form reset.
formathex | rgb | hsl | oklchinferred from valueOutput and field format; the user can switch it in the panel.
labelstringColorAccessible name of the well and the panel (falls back to an associated <label>).
swatchesstringComma-separated colors for the swatch row; an empty string hides it.
inlinebooleanPanel rendered in place, with no well or popover; mv-change fires at the end of each gesture.
opaquebooleanHides opacity (alpha is always 1).
no-recentbooleanNeither reads nor saves recent colors (shared localStorage).
placementstringbottom-startPopover placement, flipped and shifted to stay on screen.
name / disabled / readonlyStandard form behavior; readonly still opens the panel to read and copy the value.
data-variantswatchRound swatch only, no text.

Properties

NameタイプDescription
valuestringCSS 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.
hexstring“#RRGGBB”, or “#RRGGBBAA” when translucent.
modestringCurrent format (read and write).
isOpenbooleanWhether the popover is open.
stringsobjectOverrides for every visible and announced label, color names included (i18n).

Methods

NameDescription
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

NameDescription
mv-inputLive change (drag, keys, typing, swatch). detail: { value, hex, rgba }.
mv-changePopover closed with a new color, or end of a gesture when inline. The color joins the recent ones.
mv-open / mv-closePopover opened and closed.

CSS classes

NameDescription
mv-color-picker-trigger / -chip / -panel / -area / -hue / -alpha / -compare / -fields / -format / -input / -swatchGenerated parts.

CSS variables

NameDefaultDescription
--mv-color-picker-width8.5remWell width.
--mv-color-picker-panel-width17.5remPanel width.
--mv-color-picker-area-height9.5remHeight of the saturation/brightness area.
--mv-color-picker-columns10Swatches 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.

このページは AI で翻訳されています。翻訳の問題を報告