ColorPicker
스와치/field 트리거 + 스펙트럼·그리드·슬라이더 모드 팝업 — 진실원천은 HSV(+alpha)라 s=0에서도 hue가 보존되고 onChange 출력은 항상 HEX입니다. 표시 포맷(HEX/RGB/HSL) 전환·최근 색·alpha 자동 감지 포함. 외부 클릭·Escape 닫기(논모달), 비제어(defaultValue) 우선 (P3.7-B1 ColorPicker 2.0).
마지막 업데이트 2026-06-12
한눈에#
스와치/field 트리거 + 스펙트럼·그리드·슬라이더 모드 팝업. 진실원천은 HSV(+alpha)라 채도 0에서도 hue가 보존되고, onChange는 항상 HEX입니다.
- 스펙트럼·그리드·슬라이더
- HSV 원천
- HEX 출력
- 최근 색
스와치를 눌러 팝업을 열고 상단 탭으로 모드를 전환하세요
트리거는 현재 색 스와치이고, 팝업 상단의 소형 탭으로 스펙트럼(SV+Hue) ·
그리드(12×10 생성 팔레트) · 슬라이더(R/G/B 채널) 모드를 전환합니다.
진실원천은 HSV라 채도 0에서도 색조(hue)가 보존되고, onChange는 항상 대문자
HEX(alpha<1이면 #RRGGBBAA)로 발화합니다. 입력 행에는 표시 포맷 토글
(HEX/RGB/HSL) + 색 코드 입력 + 복사 버튼이 있고, 브라우저가 지원하면
스포이드(EyeDropper) 버튼이 함께 노출됩니다. 색을 바꾸고 팝업을 닫으면
'최근 색상' 그룹에 저장됩니다(localStorage, 최신순 최대 10개).
플레이그라운드#
컨트롤로 props를 조작하면 미리보기와 코드가 실시간 갱신됩니다.
import { ColorPicker } from '@wds/ui-web';
<ColorPicker />변형#
modes로 패널 모드를 제한할 수 있고 1종이면 탭이 사라집니다. trigger='field'는
스와치와 현재 HEX 텍스트를 함께 보여주는 Input 어휘 높이 버튼입니다.
format은 초기 표시 포맷일 뿐이고 패널 토글로 언제든 순환(HEX→RGB→HSL)하며,
입력 파싱은 세 포맷 모두 수용합니다. defaultValue가 alpha 명시 형식이면
showAlpha 없이 Alpha 슬라이더가 자동 노출되고, 반투명 스와치/알파 트랙 아래에는
체커보드(color.border 격자)가 깔립니다. presets를 주면 팝업 하단에 스와치
그리드가 생기고, 현재 색과 일치하는 항목은 aria-pressed로 표시됩니다.
크기#
단일 크기입니다 — 스와치 트리거는 시각 32px(space.8)에 히트 영역 44px,
field 트리거는 input.height(44px)입니다. 팝업 폭은 16rem 고정, SV 스펙트럼은
높이 10rem, 슬라이더 트랙 높이는 space.3(44px 히트)입니다.
상태#
- 트리거 Default —
color.surface+color.border-strong보더(field는input.bg/border), 스와치는 인라인 동적 색 + 체커보드 - Hover / 열림 —
color.primary보더 - Focus —
:focus-visible에color.primary2px 아웃라인 - 모드 탭 선택 —
color.surface-raised+shadow.sm(aria-selected) - 그리드 셀 선택 — 셀 인지 명도 기반 대비 링(
aria-pressed) — 밝은 색엔 어두운 링, 어두운 색엔 밝은 링 - 스펙트럼/슬라이더 썸 Focus —
color.primary18% 링 - 입력 오류 — 형식 위반 시
aria-invalid+input.border-invalid보더(값은 반영하지 않음) - 프리셋/최근 선택 — 현재 색과 일치하면
aria-pressed+color.primary아웃라인
Props#
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
defaultValue | string | '#1A75EB' | 초기 색 — #RRGGBB(AA)·rgb()/rgba()·hsl()/hsla() 수용, 이후 상태는 내부 소유(비제어). 형식 위반은 기본색 폴백 |
onChange | (hex: string) => void | — | 색 변경 콜백 — 항상 대문자 HEX(alpha<1이면 #RRGGBBAA) |
showAlpha | boolean | false | Alpha 슬라이더 노출 — defaultValue가 alpha 명시 형식(#RRGGBBAA/rgba()/hsla())이면 자동 on |
presets | ReadonlyArray<string> | — | 프리셋 스와치 그리드 — 각 항목 HEX |
modes | ReadonlyArray<'spectrum' | 'grid' | 'sliders'> | ['spectrum', 'grid', 'sliders'] | 패널 모드 구성 — 2개 이상이면 상단 소형 탭, 빈 배열은 기본 3종 폴백 |
trigger | 'swatch' | 'field' | 'swatch' | 트리거 변형 — 'field'는 스와치+HEX 텍스트(Input 어휘 높이) |
format | 'hex' | 'rgb' | 'hsl' | 'hex' | 초기 표시 포맷 — 패널 토글로 순환 전환, onChange 출력은 항상 HEX |
recentStorageKey | string | 'wds-color-picker-recent' | 최근 색 localStorage 키 — 색 변경 후 닫힘 시 저장(최신순 최대 10, SSR 안전) |
recentLabel | string | '최근 색상' | 최근 색 그룹 라벨 override |
label | string | '색상 선택' | 트리거 aria-label 접두 — '{label}: {hex}' |
className | string | — | 루트 div 클래스 |
접근성#
트리거 버튼은 aria-label="{label}: {hex}" + aria-expanded로 현재 색을
낭독합니다. 모드 탭은 APG Tabs(roving tabindex + 자동 활성화), 그리드는
role="group" 안에서 각 셀이 aria-label=HEX 버튼이며 화살표로 이동합니다.
SV 스펙트럼 썸은 role="slider" + aria-valuetext(채도/명도%), Hue·Alpha·R/G/B는
네이티브 <input type="range">입니다.
| 키 | 동작 |
|---|---|
트리거 Enter / Space | 팝업 토글 (네이티브 button) |
모드 탭 ← / → / Home / End | 탭 포커스 이동 + 자동 활성화 (APG) |
스펙트럼 썸 ← / → | 채도(s) 1%p 감소 / 증가 |
스펙트럼 썸 ↑ / ↓ | 명도(v) 1%p 증가 / 감소 |
그리드 셀 ← → ↑ ↓ / Home / End | roving 셀 이동 (행 폭 12) |
| Hue/Alpha/R/G/B 슬라이더 | 네이티브 range 키보드(화살표/Home/End) |
Escape | 팝업 닫기 (논모달 — 포커스는 건드리지 않음) |
- 외부 클릭·Escape로 닫히는 논모달입니다(Popover 계약) — 포커스 트랩 없음
- 색 코드 입력은 형식 위반(
aria-invalid)이면 값을 반영하지 않습니다(경계 검증 — HEX/RGB/HSL 모두 파싱) - 동적 색(스와치·그라디언트)은 인라인 style이 소유하고 CSS 파일은 토큰만 씁니다(DD-4)
- 복사 버튼은 CopyButton 합성 — 결과를
aria-live로 공지합니다
토큰#
component 토큰 없이 semantic(+input 어휘)을 직접 소비합니다(신설 기준 §4 미충족 — 동적 색은 토큰이 아닌 데이터 값).
| 속성 | 토큰 |
|---|---|
| 트리거 | color.surface · color.border-strong — hover/열림 color.primary · radius.md · 크기 space.8 |
| field 트리거 | input.bg/fg/border · input.height · input.radius · font.mono |
| 팝업 | color.surface-raised · color.border · radius.md · shadow.lg · z.dropdown |
| 모드 탭 | color.surface-muted 트랙 — 선택 color.surface-raised + shadow.sm · font-size.caption |
| 그리드 셀 | 선택 링 black/white(명도 대비) — Focus color.focus-ring 아웃라인 |
| 체커보드 | color.border 반복 그라디언트 (space.2 격자) |
| 스펙트럼 썸 | white · shadow.sm — Focus color.primary 18% 링 |
| 슬라이더 썸 | white · shadow.md — Focus color.primary 18% 링 |
| 색 코드 입력/포맷 토글 | input.bg/fg/border · font.mono — 오류 input.border-invalid |
| 스포이드 | color.text-muted · color.border — hover color.primary |
| 프리셋/최근 | color.border — 선택/Focus color.focus-ring 아웃라인 · 캡션 color.text-muted |
| 모션 | duration.fast + ease.out/standard |