Color Picker <mv-color-picker>

라이트 디스미스 팝오버를 여는(또는 인라인으로 놓이는) 컬러 웰: 채도/명도 영역, 색조와 불투명도 슬라이더, HEX/RGB/HSL/OKLCH 전환이 있고 모든 CSS 색상을 받는 텍스트 필드 하나, 스포이트, 견본, 최근 색상을 제공합니다.

작동 방식

라이트 디스미스 팝오버를 여는(또는 인라인으로 놓이는) 컬러 웰: 채도/명도 영역, 색조와 불투명도 슬라이더, HEX/RGB/HSL/OKLCH 전환이 있고 모든 CSS 색상을 받는 텍스트 필드 하나, 스포이트, 견본, 최근 색상을 제공합니다. 모든 슬라이더는 읽기 쉬운 색상 이름을 알려 주며, 요소 자체가 값이 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로 번역되었습니다. 번역 문제 신고