ComponentsP3 본문

TimePicker

Input형 트리거 + 시간 목록 드롭다운 — interval·minTime·maxTime으로 'HH:mm' 옵션을 생성하는 비제어 컴포넌트입니다. mobile이면 BottomSheet 목록으로 전환됩니다 (DK 사양 승격).

마지막 업데이트 2026-06-11

한눈에#

Input형 트리거 + 시간 목록 드롭다운으로 시각만 고릅니다 — interval·minTime/maxTime으로 'HH:mm' 옵션을 생성합니다.

  • Input형 트리거 + 시간 목록
  • interval·minTime·maxTime
  • list·dial 모드
  • 비제어 + BottomSheet 모바일

트리거 높이는 input.height로 폼 줄맞춤 — list는 인터벌 목록, dial은 시→분 시계판

사용 시점#

회의 시작·마감처럼 시각만 고르면 TimePicker — 날짜나 날짜+시각은 다른 컴포넌트입니다.

쓴다

회의 시작·마감 시각처럼 시각만(interval·minTime/maxTime으로 업무 시간대 제한)

대신 DatePicker

날짜를 고르거나 날짜+시각을 함께 잡을 때(나란히 배치)

플레이그라운드#

컨트롤로 props를 조작하면 미리보기와 코드가 실시간 갱신됩니다.

import { TimePicker } from '@wds/ui-web';

<TimePicker />

변형#

interval · minTime/maxTime — 업무 시간 15분 간격 · defaultValue

옵션은 minTime(기본 '00:00')부터 interval분 간격으로 maxTime(기본 '23:59', 포함)까지 생성됩니다. 형식이 어긋난 defaultValue('25:99' 등)는 무시되고 placeholder가 표시됩니다. 팝업은 트리거 아래에 뜨고, 뷰포트 하단 공간이 부족하면 위로 플립됩니다.

표시 모드 (ADR-012 Track C)#

mode가 오버레이 내용을 가릅니다 — 기본 'list'은 위의 인터벌 목록(기존 동작), 'dial'시계판 2단계 선택(M3 dial)입니다. 두 모드는 같은 트리거를 공유합니다.

dial — 시 → 분 2단계 시계판 + 직접 입력 보조

dial은 시(0–23, 바깥/안쪽 두 링)를 먼저 고른 뒤 분(5분 단위)을 고르면 HH:mm으로 확정합니다. 시계판 위의 HH:mm 직접 입력 필드가 키보드 경로를 제공합니다 — 유효한 시간을 입력하고 Enter로 확정합니다. compact 뷰포트(mobile)에서는 BottomSheet 안에 같은 시계판이 렌더됩니다. min/max 범위 제한은 list 모드에만 적용됩니다.

크기#

단일 크기입니다 — 트리거 높이는 input.height(44px)로 Input과 같은 폼 컨트롤 줄맞춤이고, 최소 폭은 'HH:mm' + 시계 아이콘 기준 9rem(시간 전용이라 Select 14rem보다 좁음)입니다. 리스트는 최대 16rem 높이에서 스크롤됩니다.

상태#

Disabled
  • Focus — 트리거 :focus-visiblecolor.primary 아웃라인 링
  • 열림input.border-focus 보더 + aria-expanded="true"
  • 활성 옵션color.surface-hover 배경(마우스 호버도 활성을 따라감)
  • 선택 옵션aria-selected + color.primary-text 잉크
  • Disabledinput.bg-disabled 배경 + 커서 차단

비제어 컴포넌트입니다 — defaultValue로 시작하고 선택 시 onChange('HH:mm')로 알립니다. 같은 값 재선택은 발화하지 않습니다.

모바일#

DK 모바일 재활용 표준입니다 — mobile을 켜면 트리거 클릭 시 데스크톱 팝업 대신 BottomSheet(height half)가 열리고, 시간 리스트는 role="listbox" 의미론을 유지한 채 시트 안에 렌더됩니다. 단일 선택이므로 항목을 누르는 즉시 확정되고 시트가 닫힙니다(임시 상태 없음). 시트 제목은 mobileTitle, 없으면 placeholder가 채워집니다. 라이브 데모는 데스크톱 뷰포트라 코드로 안내합니다.

<TimePicker
  mobile
  mobileTitle="시작 시간 선택"
  aria-label="시작 시간"
  interval={15}
  minTime="09:00"
  maxTime="18:00"
  onChange={(time) => applyStartTime(time)}
/>

닫힘 경로(배경 클릭·Escape·닫기 버튼·핸들 드래그 다운)와 포커스 복원은 BottomSheet 계약을 그대로 따릅니다 — 값 변경 없이 닫힙니다.

Props#

Prop타입기본값설명
defaultValuestring초기 선택 시간 'HH:mm' — 형식이 어긋나면 무시 (비제어)
onChange(value: string) => void선택 변경 콜백 — 같은 값 재선택은 발화하지 않음
intervalnumber30옵션 간격(분) — 1 미만/비정상 값은 30으로 대체
minTimestring'00:00'목록 시작 시간 'HH:mm'
maxTimestring'23:59'목록 끝 시간 'HH:mm' (포함)
placeholderstring'시간 선택'선택 전 트리거에 표시되는 문구
mode'list' | 'dial''list'list: 인터벌 목록(기본) · dial: 시계판 2단계(시→분) + 직접 입력
mobilebooleanfalsetrue면 팝업 대신 BottomSheet 목록 — 탭 즉시 확정 (DK 모바일 표준)
mobileTitlestring시트 제목 — 기본 placeholder
…restOmit<ButtonHTMLAttributes, 'onChange' | 'value' | 'defaultValue'>aria-label · disabled 등은 트리거 button으로 전달

접근성#

트리거가 role="combobox" + aria-haspopup="listbox", 팝업이 role="listbox"입니다. 포커스는 항상 트리거에 머물고 aria-activedescendant가 활성 옵션 id를 가리킵니다(데스크톱 팝업 전용 — mobile 시트는 BottomSheet 포커스 트랩 계약을 따름).

키보드 열기는 데스크톱·모바일 두 표면 모두에서 동작합니다(WCAG 2.1.1) — mobile/compact에서도 트리거에 포커스를 두고 ··Enter·Space를 누르면 BottomSheet가 열립니다. 시트가 열린 뒤의 포커스 트랩·Escape 닫기는 BottomSheet 계약이 담당합니다.

동작
/ / Enter / Space (닫힘)열기 — 선택(없으면 첫) 옵션 활성
/ (열림)활성 옵션 이동 — 양 끝에서 클램프
Enter / Space활성 옵션 선택 + 닫기 + 트리거 포커스 유지
Escape값 변경 없이 닫기
Tab닫고 기본 포커스 이동

외부 클릭으로도 닫히며, 선택 옵션은 aria-selected로 보고됩니다.

토큰#

component 토큰 없이 Input의 component 토큰(input.*)과 semantic을 직접 소비합니다(신설 기준 §4 미충족 — Select과 같은 dropdown 어휘).

속성토큰
트리거input.bg/fg/border/height/radius · placeholder input.placeholder
포커스color.focus-ring 아웃라인 · 열림 보더 input.border-focus
시계 아이콘icon.size-md · color.text-subtle
팝업color.surface-raised · radius.md · shadow.lg · z.dropdown
옵션 활성/선택color.surface-hover/selected · 선택 잉크 color.primary-text
눌림(옵션·시계판 숫자)color.surface-pressed (선택 배경은 안 덮음)
옵션 높이control.height-sm
비활성input.bg-disabled · color.text-placeholder
모션duration.fast + 팝업 등장 ease.emphasized-decelerate / ease.standard

관련#