Groo Design

Date Picker

날짜 · 기간 · 여러 날을 고르는 달력. 날짜 칸(Input Button)을 누르면 1280 미만은 아래 시트 · 이상은 칸 아래 팝오버로 열리고, "완료" 로 넣는다 — 날짜 고르기가 그 화면의 주된 일이면 화면에 바로 펼친다(지금 쓰는 곳은 없다 — "어디에 놓나"). 날짜를 치는 칸은 두지 않는다. 시각은 Time Picker 를 날짜 칸 옆에 나란히, 달만 고를 때는 Wheel Picker 다.

구조는 당근 SEED Date Picker(Apache-2.0)를 따른다 — 머리(연 · 월 제목 · 이전 · 다음) · 요일 줄 · 날짜 칸(원 · 숫자) · 기간 띠, 하루 · 기간 · 여러 날, 한 달 · 두 달 · 이어지는 달. 값은 groo 토큰이고, SEED 와 다른 자리는 맨 아래 "SEED 와 다른 점" 에 적었다(2026-10-03 사용자 결정). 옛 Calendar 스펙을 대신한다.

수치 원본은 date-picker.yaml이다. 수치 표 자리([표: …])와 그림 자리([그림: …])는 사이트가 그 파일로 그린다 — GitHub 에서는 그 파일 · 그림 코드로 가는 링크로 보인다.

9:41
일정 추가
10월 2일 (금)
팀 회의
날짜 선택
desk.groo.app
통계
9월 1일~9월 30일
9:41
저축 목표
3,000,000원
2027년 3월 31일 (수)
날짜 선택
desk.groo.app
통계
9월 1일~9월 30일
일정 날짜 · 통계 기간 · 저축 기한 — 라이트 · 다크

직접 골라 보기

고르기(하루 · 기간 · 여러 날) · 여는 자리(시트 · 팝오버) · 막힌 날 · 빠른 기간을 고르면 스펙대로 그린 달력과 그 코드가 바뀐다. 실제로 날짜를 누르고 "완료" 로 칸에 넣을 수 있다.

9:41
일정 추가
날짜 선택
날짜 선택

날짜를 누르고 "완료" 를 누르면 칸에 들어가요. 바깥 · 닫기 · Esc 는 고르던 것을 버려요.

고르기 selection
여는 자리
막힌 날
빠른 기간 presets빠른 기간은 기간(range)에서만 — 달력 위 칩 한 줄.
모드
브랜드
import { DatePicker } from "@/components/ui/date-picker"

// 1280 미만 — BottomSheetContent 의 본문 — useInputButtonSurface(input-button.md)
<DatePicker
  selection="single"
  autoFocus
  value={draft}
  onValueChange={setDraft}
/>
<Button disabled={!draft} onClick={apply}>완료</Button>

Anatomy

하루 — 팝오버(한 달)
기간 — 팝오버(두 달 · 빠른 기간)
ⓐ Presetsⓑ Headerⓒ Titleⓓ Nav Buttonⓔ Weekdayⓕ Cellⓖ Dayⓗ Range Bandⓘ Footer
달력은 머리 · 요일 줄 · 날짜 칸, 기간이면 띠와 빠른 기간 칩 줄
부위설명
ⓐ Presets빠른 기간 — 기간 달력 위 칩 한 줄. 누르면 달력에 칠한다.
ⓑ Header머리 — 왼쪽 연 · 월 제목, 오른쪽 이전 · 다음.
ⓒ Title연 · 월 제목 — 누르면 날짜 자리에 연 · 월 휠이 뜬다.
ⓓ Nav Button이전 · 다음 — 한 달씩.
ⓔ Weekday요일 줄 — "일" … "토".
ⓕ Cell날짜 칸 — 칸 전체가 누르는 자리.
ⓖ Day날짜 원 · 숫자 — 오늘 · 고름 · 막힘을 그린다.
ⓗ Range Band기간 띠 — 시작 · 끝 원 사이.
ⓘ Footer바닥 — "완료"(기간은 "초기화" + "완료"). 시트 · 팝오버의 바닥이다.

부위

부위설명
root달력 — 시트 · 팝오버의 본문
presets빠른 기간 — 기간 달력 위 칩 한 줄(하나 고르기)
header머리 — 왼쪽 연 · 월 제목, 오른쪽 이전 · 다음
title연 · 월 제목 — 누르면 날짜 자리에 연 · 월 휠
titleIcon제목 셰브론 — 휠이 열리면 위로
navButton이전 · 다음 — 한 달씩(두 달 보기는 한 달씩, PageUp · PageDown 은 두 달)
weekday요일 줄 — "일" … "토", 읽는 이름은 "일요일" …
cell날짜 칸 — 칸 전체가 누르는 자리
dayVisual날짜 원 — 오늘 · 고름 · 호버
dayLabel날짜 숫자
rangeBand기간 띠 — 시작 · 끝 원 사이를 잇는다
monthLabel달 이름 — 이어지는 달 · 두 달 보기에서 달마다
wheel연 · 월 휠 — 요일 줄과 날짜 자리를 덮는다(Wheel Picker)
fog아래 안개 — 이어지는 달의 아래 끝
footer바닥 — "완료"(기간은 "초기화" + "완료")
focusRing키보드 포커스 링(웹)

Properties

머리 · 요일 · 날짜 칸

머리 · 요일 줄 · 날짜 줄은 모두 48 이다. 날짜 칸은 달력 폭을 7로 나눈 폭에 높이 48 이고 칸 전체가 누르는 자리다 — 원 42 는 칸 위 3 에 놓여 원 · 띠끼리 6 떨어진다. 숫자는 16 / 22 · 500, 요일은 14 / 19 · 500 fg-neutral-subtle. 제목은 16 / 22 · 700 에 셰브론 20, 이전 · 다음은 Button ghost 40(아이콘 18)을 오른쪽 끝에 붙인다.

달력은 늘 6주다 — 앞뒤 달 날짜를 흐리게 채워 달을 넘겨도 머리 · 바닥이 움직이지 않는다. 앞뒤 달 날짜는 보이기만 하고 누르지 못한다(보조 기술에도 숨긴다) — 다른 달은 이전 · 다음 · 화살표 키로 넘긴다.

칸 전체가 누르는 자리 — 원 42 은 칸 위 3 · 가운데라 원 · 띠끼리 6 떨어진다. 숫자 16 / 22 · 500, 요일 14 / 19 · 500. 9월 27일~30일 · 11월 1일~7일(앞뒤 달)은 흐리게 채우기만 하고 누르지 못한다 — 늘 6주라 달을 넘겨도 높이가 그대로다.

360 화면 — 시트 달력 312칸 44.6 · 원 42
320 화면 — 시트 달력 272칸 38.9 · 원 36.9 — 44 보다 좁아 칸 폭 − 2
칸 48 · 원 42 · 숫자 16 · 머리 48 · 6주 — 앞뒤 달은 흐리게

공통

부위속성값비고
root너비336px팝오버 — 칸 48 × 7. 시트는 시트 폭 − 좌우 24 · 24(360 화면 312 · 칸 44.6)
root배경color-bg-layer-floating #FFFFFF · 다크 #2D3346
presets칩Chip outlineStrong medium 36하나 고르기(라디오) — 고른 칩은 짙은 채움, 달력에서 다른 날을 누르면 풀린다. 이름 · 범위는 date-picker.md 의 '빠른 기간'
presets간격spacing-between-chips 8px칩 사이 8 — 시트는 한 줄 가로 스크롤(화면 끝까지), 팝오버는 줄바꿈
presets아래 여백spacing-x3 12px칩 줄 ↔ 머리 12
header높이48px최소 — 글자가 크면 그만큼만 늘어난다. 칸 · 머리 · 요일 줄 · 원 · 이전 · 다음은 px, 글자만 배율(SEED, 03-C 1B)
title글자text-t5 16px / 22px
title굵기700
title글자·아이콘color-fg-neutral #1A1F2E · 다크 #F5F6FA
title좌우 여백spacing-x1 4px제목 글자는 머리 왼쪽에서 4 — 누르는 자리는 머리 높이 48 전체
title간격spacing-x1 4px글자 ↔ 셰브론
title모서리radius-r2 8px바탕이 없어 초점 링에만 보인다
titleIcon크기20pxlucide chevron-down
titleIcon색color-fg-neutral #1A1F2E · 다크 #F5F6FA
navButton크기40pxButton ghost iconOnly medium 을 px 로 — 글자 크기를 따르지 않는다(03-C 1B). 둘 사이 0, 머리 오른쪽 끝, 누르는 영역 44
navButton아이콘 크기18pxlucide chevron-left · chevron-right
navButton색color-fg-neutral #1A1F2E · 다크 #F5F6FA
weekday높이48px최소 — 글자가 크면 그만큼만 늘어난다(03-C 1B)
weekday글자text-t4 14px / 19px
weekday굵기500
weekday글자·아이콘color-fg-neutral-subtle #62697A · 다크 #A2A8B7
cell높이48px최소(SEED dateCell minHeight) — 글자가 크면 그만큼만 늘어난다(03-C 1B): max(48, 숫자 줄 높이 + 위아래 3 · 3) — 날짜 버튼 · 앞뒤 달 숫자가 위아래 3 을 가진다(200% 44 + 6 = 50 · 달력 396). 폭은 달력 폭 ÷ 7 — 칸 전체가 누르는 자리, 칸 사이 0
cell주 수6늘 6주 — 달을 넘겨도 머리 · 바닥이 움직이지 않는다(이어지는 달만 그 달의 주 수)
cell커서pointer
dayVisual크기42pxpx — 글자 크기를 따르지 않는다(03-C 1B, SEED). 칸 위 3 · 가로 가운데 — 원 · 띠끼리 6 떨어진다. 칸이 44 보다 좁으면(320 화면) 칸 폭 − 2
dayVisual모서리radius-full 9999px
dayVisual배경transparent
dayVisual전환 대상background-color
dayVisual전환 시간motion-duration-color-transition 150ms
dayVisual전환 곡선motion-ease-easing cubic-bezier(0.35, 0, 0.35, 1)
dayLabel글자text-t5 16px / 22px숫자 폭을 같게(tabular-nums)
dayLabel굵기500
dayLabel글자·아이콘color-fg-neutral-muted #535866 · 다크 #B7BDCC
rangeBand높이42px칸 위 3 — 원과 같은 높이(칸이 좁아 원이 줄면 띠도 같이). 시작 칸은 원 가운데부터 오른쪽, 끝 칸은 왼쪽부터 원 가운데까지, 사이 칸은 칸 폭 전체 — 줄 끝에서 둥글리지 않고 칸 끝에서 끊는다
rangeBand배경color-bg-neutral-weak #F5F6FA · 다크 #353B4D
monthLabel높이48px최소 — 글자가 크면 그만큼만 늘어난다(03-C 1B)
monthLabel글자text-t5 16px / 22px
monthLabel굵기700
monthLabel글자·아이콘color-fg-neutral #1A1F2E · 다크 #F5F6FA
wheel높이336px요일 줄 + 6주 자리를 덮는다 — 높이는 요일 줄 + 6 × 칸이라 글이 크면 달력을 따라 늘어난다(100% 요일 줄 48 + 6주 288 · 200% 48 + 50 × 6 → 348, 열고 닫아도 달력 높이가 그대로). Wheel Picker medium 44 × 7 = 308 을 가운데에(100% 위아래 14). 열린 동안 이전 · 다음은 막힌다
wheel칼럼연 120 · 월 96연은 오른쪽 · 월은 왼쪽 정렬로 가운데에 모은다(SEED 와 같다) — 항목은 "2026년" · "10월"
wheel배경color-bg-layer-floating #FFFFFF · 다크 #2D3346
footer위 여백spacing-x4 16px팝오버 — 달력 아래 16, 버튼 small 36 오른쪽 맞춤. 시트는 Bottom Sheet 바닥(위 12 · 아래 16, large 48 — 하나면 폭 전체, 둘이면 반씩)

팝오버의 달력은 336(칸 48 × 7), 시트는 시트 폭에서 좌우 24 를 뺀 폭이다(360 화면 312). 칸이 44 보다 좁으면(320 화면) 원을 칸 폭 − 2 로 줄인다.

글자 크기 설정은 글자(숫자 · 요일 · 제목)만 따른다. 칸 · 머리 · 요일 줄은 최소 48 이고 글이 더 크면 그만큼만 늘어나며, 원 42 · 이전 · 다음 40 은 px 그대로다(SEED — dateCell minHeight). 날짜 칸은 숫자 줄 높이에 위아래 3 · 3 을 더한 높이와 48 중 큰 쪽이다 — 날짜 버튼과 앞뒤 달 숫자가 위아래 3 을 가지므로 숫자 줄이 원 42 를 넘는 큰 글자에서 칸이 줄 높이 + 6 이 된다(100% 48 · 200% 44 + 6 = 50). 웹 · 앱이 같은 모양이다. 글자 200% 에서 달력은 396(머리 48 · 요일 48 · 칸 50 × 6) — 시트 안에 6주가 다 들고 제목이 한 줄로 보인다. 이어지는 달의 달 높이(이름 줄 + 칸 × 주 + 16)도 같은 칸 높이로 셈하고, 배율이 바뀌면 다시 재서 보던 달로 맞춘다. 연 · 월 휠 자리도 요일 줄 + 6 × 칸이라 함께 늘어난다(100% 336 · 200% 348) — 제목을 눌러 휠을 열고 닫아도 달력 높이가 그대로다(2026-10-22 I-04 검수 — 레시피가 칸에 위아래 3 을 두지 않아 200% 에서 384 였다). 대가 — 두 자리 숫자(32px)가 원 42 를 채워 이웃 숫자와 약 6 떨어진다(SEED 와 같은 값)(2026-10-21 사용자 결정 — 03-C 1B, 비교 페이지 https://claude.ai/artifact/3nWUZCYpPh2Cg3uXc3DKtp).

Selection

값쓰는 곳
single날짜 하나 — 일정 · 거래 · 할 일 마감 · 저축 기한 · 환불일
range기간 — 통계 · 가계부 필터 · 내보내기 · 검색 · 업무 보고 · 공지 · 유효기간
multiple여러 날 — 따로 고른 날들. 지금 쓰는 곳은 없다(SEED 와 같게 둔다)

고르기

selection설명
single (기본)하루 — 날짜 · 기한 · 약속일
range기간 — 시작 · 끝, 같은 날을 두 번 누르면 하루짜리 기간
multiple여러 날 — 따로 고른 날들, 띠로 잇지 않는다. 다시 누르면 풀린다

Visible Range

하루 · 여러 날은 한 달(month)이다. 기간은 여는 자리에 따라 바뀐다 — 1280 미만 시트는 달이 위아래로 이어지고(continuous, 스크롤로 달을 넘긴다 · 요일 줄이 위에 붙는다 · 아래 안개 96), 1280 이상 팝오버는 두 달을 나란히(twoMonths, 사이 24 — 팝오버 폭 744 는 Popover 최대 480 의 예외다).

twoMonths — 두 달 나란히1280 이상 팝오버의 기간 · 336 + 24 + 336 = 696(팝오버 744 — Popover 최대 480 의 예외)
month — 한 달하루 · 여러 날 · 팝오버 336(칸 48 × 7) · 늘 6주
9:41
통계
9월 1일~9월 30일
기간 선택
continuous — 이어지는 달1280 미만 시트의 기간 · 요일 줄이 위에 붙고 아래 안개 96
한 달 · 두 달 나란히 · 이어지는 달

보이는 범위

visibleRange높이너비칸 간격header 높이title 글자weekday 자리cell 주 수monthLabel 좌우 여백fog 높이설명
month (기본)—————————한 달 — 하루 · 여러 날, 그리고 시트 · 팝오버가 아닌 자리
twoMonths—696px — 336 + 24 + 336 — 팝오버 폭 744(Popover 최대 480 의 예외)spacing-x6 24px — 두 달 사이 2448px — 머리를 나누지 않는다 — 달 이름은 달마다 가운데, 이전 버튼은 첫 달 왼쪽 끝 · 다음 버튼은 둘째 달 오른쪽 끝(위 4)text-t5 16px / 22px — 달 이름은 누르지 않는다 — 연 · 월 휠이 없다————두 달 나란히 — 1280 이상 팝오버의 기간
continuous시트에 맞춘다 — 시트를 화면 높이의 90% 로 열고 머리 · 칩 줄 · 바닥을 뺀 높이 — 그 안에서 달이 위아래로 이어진다(스크롤바 숨김)——0px — 머리 없음 — 스크롤이 달을 넘긴다. 연 · 월 휠도 없다—sticky — 맨 위에 붙는다 — 달마다의 요일 줄은 없다그 달의 주 수 — 4 ~ 6 — 앞뒤 달 날짜는 비운다(달이 이어져 다음 달이 바로 아래에 있다)spacing-x1 4px — 왼쪽 정렬, 달 아래 1696px — 아래 끝 — 투명에서 바탕색으로달이 위아래로 이어진다 — 1280 미만 시트의 기간

State

상태모습
enabled숫자 fg-neutral-muted · 원 없음
hovered웹 — 마우스를 올린 날짜에 옅은 원(bg-neutral-weak-alpha-pressed — SEED 투명 색, 바탕 1.15 · 다크 1.77). 오늘 · 기간 사이 날 위에서는 불투명 bg-neutral-weak-pressed
pressed터치 — 누르는 동안 같은 원. 날짜는 줄지 않는다
focused키보드 초점이 온 날짜의 원 둘레 안쪽 2px 링 — 웹 · 앱(앱은 하드웨어 키보드 · 스위치 접근일 때만)
today옅은 원(bg-neutral-weak) + 숫자 700 · fg-neutral
selected짙은 원(bg-neutral-inverted) + 숫자 fg-neutral-inverted — 하루 · 여러 날의 고른 날, 기간의 시작 · 끝
inRange기간의 사이 날 — 원 없이 띠(bg-neutral-weak)
outside앞뒤 달 — 흐린 숫자(fg-disabled), 누르지 못함
disabled고를 수 없는 날 — 흐린 숫자 + 취소선. 초점은 간다(aria-disabled)
readOnly확정된 시작일(기간 늘리기) — 흐린 채움(stroke-neutral-solid) + 숫자 fg-neutral-inverted, 누르지 못함. 그 앞의 날은 끝이 될 수 없어 막힌 날로 그린다
보통
호버(마우스)
누름(터치)
키보드 초점
오늘
고름
기간 — 시작 · 사이 · 끝
앞뒤 달
막힘
읽기 전용 시작일
오늘을 고르면 — 짙은 원, 굵기는 남는다
기간 안의 오늘 — 원 없이 굵은 숫자
오늘 위 호버 — 한 단계 짙은 원
기간 사이 위 호버 — 한 단계 짙은 원
기간 안의 막힌 날 — 띠 위 흐린 취소선
오늘인데 막힌 날 — 원 없이 굵은 숫자 + 취소선
고른 날인데 막힌 날 — 고른 모양 + 취소선
시작만 고른 막힌 날 — 취소선 없음
라이트
보통
호버(마우스)
누름(터치)
키보드 초점
오늘
고름
기간 — 시작 · 사이 · 끝
앞뒤 달
막힘
읽기 전용 시작일
오늘을 고르면 — 짙은 원, 굵기는 남는다
기간 안의 오늘 — 원 없이 굵은 숫자
오늘 위 호버 — 한 단계 짙은 원
기간 사이 위 호버 — 한 단계 짙은 원
기간 안의 막힌 날 — 띠 위 흐린 취소선
오늘인데 막힌 날 — 원 없이 굵은 숫자 + 취소선
고른 날인데 막힌 날 — 고른 모양 + 취소선
시작만 고른 막힌 날 — 취소선 없음
다크
보통 · 호버 · 오늘 · 고름 · 기간 · 앞뒤 달 · 막힘 · 읽기 전용 · 키보드 초점 — 라이트 · 다크

상태

상태cell 커서dayVisual 배경취소선dayLabel 글자·아이콘dayLabel 굵기링 두께링 간격링 색
enabled 이번 달 날짜pointertransparent—color-fg-neutral-muted #535866 · 다크 #B7BDCC500———
hovered 웹 — 마우스를 올린 날짜의 원(고운 포인터만)pointercolor-bg-neutral-weak-alpha-pressed #00000010 · 다크 #FFFFFF2E — SEED 투명 색 — 바탕 1.15 · 다크 1.77(2026-10-21 03-C 2B). 마우스(고운 포인터)만 — 축소 없음. 오늘(옅은 원) · 기간 사이 날(띠) 위에서는 불투명 bg-neutral-weak-pressed(투명 색을 띠에 얹으면 또 다른 색이 된다). 막힌 날 · 읽기 전용 · 앞뒤 달에는 없다—color-fg-neutral-muted #535866 · 다크 #B7BDCC500———
pressed 누르는 동안 원(터치) — 날짜는 줄지 않는다pointercolor-bg-neutral-weak-alpha-pressed #00000010 · 다크 #FFFFFF2E — 터치는 누르는 동안 — 오늘 · 기간 사이 날 위에서는 불투명 bg-neutral-weak-pressed. 날짜는 줄지 않는다(이전 · 다음은 Button 처럼 2px 축소)—color-fg-neutral-muted #535866 · 다크 #B7BDCC500———
focused 키보드 초점이 온 날짜에 링(웹 · 앱 — 앱은 하드웨어 키보드 · 스위치 접근, 03-C 4A)pointertransparent—color-fg-neutral-muted #535866 · 다크 #B7BDCC5002px-2px — 원 자리(42) 안쪽 — 칸이 아니라 원 둘레color-stroke-focus-ring #1A1F2E · 다크 #F5F6FA
today 오늘 — 옅은 원 + 숫자 굵게pointercolor-bg-neutral-weak #F5F6FA · 다크 #353B4D—color-fg-neutral #1A1F2E · 다크 #F5F6FA700 — 색이 아니라 굵기로도 알린다 — 고른 날 · 기간 안에서도 굵기는 남는다———
selected 고른 날 · 기간의 시작 · 끝 — 짙은 원pointercolor-bg-neutral-inverted #1A1F2E · 다크 #F5F6FA — 하루 · 여러 날의 고른 날, 기간의 시작 · 끝 — 오늘이어도 이 모양이 이긴다(굵기는 남는다)—color-fg-neutral-inverted #FFFFFF · 다크 #242938500———
inRange 기간의 사이 날 — 띠pointertransparent — 띠가 바탕 — 오늘이어도 원은 그리지 않는다(굵기만 남는다)—color-fg-neutral-muted #535866 · 다크 #B7BDCC500———
outside 앞뒤 달 날짜 — 흐리게 보이기만, 누르지 못한다defaulttransparent—color-fg-disabled #8A91A0 · 다크 #838997 — 앞뒤 달 날짜 — 보이기만 하고 누르지 못한다(숫자만 보조 기술에 숨기고 칸은 남겨 요일 짝을 지킨다). 기간 띠도 그리지 않는다. 다른 달은 이전 · 다음 · 화살표 키로500———
disabled 고를 수 없는 날 — 흐린 글자 + 취소선, 초점은 간다not-allowedtransparentline-through — 고를 수 없는 날 — 흐린 색과 함께 취소선. aria-disabled 라 키보드 초점은 간다color-fg-disabled #8A91A0 · 다크 #838997500———
readOnly 확정된 시작일(기간 늘리기) — 흐린 채움, 누르지 못한다defaultcolor-stroke-neutral-solid #767C8B · 다크 #838997 — 확정된 시작일 — 채움은 남기고 톤을 낮춘다(SEED palette gray-600 의 역할 짝). 누르지 못하지만 초점은 간다—color-fg-neutral-inverted #FFFFFF · 다크 #242938500———

상태가 겹칠 때

  • 고름이 이긴다 — 오늘을 고르면 짙은 원이다. 오늘의 굵기(700)는 남는다.
  • 기간 안의 오늘은 원 없이 띠 위에 굵은 숫자다.
  • 막힌 날이 기간 안에 있으면 띠는 그대로 깔리고 숫자만 흐린 취소선이다. 미완성 기간(시작만 고름)의 시작일이 막힌 날이어도 시작 원 위에는 취소선을 긋지 않는다.
  • 오늘인데 막힌 날은 원 없이 굵은 숫자 + 취소선, 고른 날인데 막힌 날은 고른 모양 + 취소선이다.
  • 막힌 날 · 읽기 전용 · 앞뒤 달에는 호버 원이 없다.

모션

전환시간곡선대상비고
날짜 바탕motion-duration-color-transition 150msmotion-ease-easing cubic-bezier(0.35, 0, 0.35, 1)background-color
제목 셰브론motion-duration-d3 150msmotion-ease-easing cubic-bezier(0.35, 0, 0.35, 1)rotate 0 → 180°연 · 월 휠이 열리면 — 휠과 날짜는 모션 없이 바뀐다
누름 — 이전 · 다음motion-duration-pressed-scale 150msmotion-ease-pressed-scale cubic-bezier(0, 0, 0.15, 1)scaleButton 과 같은 2px 거리 축소 — 날짜 칸은 줄지 않는다

Guidelines

날짜는 고르게 한다

날짜를 치는 칸은 두지 않는다 — 날짜 칸은 Input Button 이고, 누르면 이 달력이 열린다. 고르는 동안 칸 값은 그대로이고 "완료" 를 누를 때 들어간다. 바깥 · 끌어내리기 · Esc 로 닫으면 고르던 것은 버린다. 열 때는 칸의 값에서 시작한다 — 비었으면 오늘이 든 달을 열고 오늘을 짚기만 한다(고른 것처럼 칠하지 않는다). "완료" 는 하루를 고르기 전, 기간의 끝을 고르기 전에는 막힌다.

9:41
일정 추가
10월 2일 (금)
팀 회의
날짜 선택
이렇게 — 고르는 동안 칸은 그대로(10월 2일) — "완료" 를 누를 때 10월 15일 (목) 이 들어간다
9:41
일정 추가
10월 15일 (목)
팀 회의
날짜 선택
이렇게 하지 않는다 — 날짜를 누르는 순간 칸에 넣고 닫는다 — 잘못 누른 날이 그대로 들어가고, 기간은 시작만 고르고 닫힌다
칸을 누르면 시트 · 팝오버의 달력, "완료" 로 칸에 들어간다

어디에 놓나 — 시트 · 팝오버 · 펼친 달력

SEED 는 "날짜 선택이 화면에서 차지하는 비중과 플랫폼에 따라" 놓는 자리(Layout)를 고른다 — 폼의 칸이면 시트 · 팝오버, 날짜 고르기가 그 화면의 핵심 작업이거나 여러 단계 흐름의 한 단계면 화면에 바로 펼친 달력(Inline)이다. 시트 · 팝오버의 1280 은 사용자 결정이고, 펼친 달력은 SEED 와 같게 두되 지금 쓰는 곳은 없다(multiple · 읽기 전용과 같은 결 — 2026-10-22 사용자 결정 1C · 2B · 3B, https://claude.ai/artifact/Mag1tEv51MdQHdy1o8hY3L).

상황고를 것확정
폼의 날짜 칸 — 폰 · 1280 미만(거래 · 일정 · 할 일 마감 · 환불일)Input Button → 아래 시트 + 달력(한 달)시트 바닥 "완료"
같은 칸 — 1280 이상 웹Input Button → 칸 아래 팝오버 + 달력(336)팝오버 바닥 "완료"
기간(통계 · 내보내기 · 검색)칸 하나 → 시트는 이어지는 달 · 팝오버는 두 달 + 빠른 기간 칩"초기화" + "완료"
날짜 고르기가 그 화면의 주된 일 · 여러 단계 흐름의 한 단계펼친 달력(Inline) — 화면에 바로 둔다. 지금 쓰는 곳은 없다화면의 "다음" · "완료"
시각 칸Input Button → Time Picker(시트 · 팝오버). 날짜와 함께면 날짜 칸 옆에 시각 칸(사용자 결정)"완료"
날짜가 주된 단계이고 시각은 덧붙는 값달력은 펼치고, 시각은 그 아래 칸 → 시트(SEED — Time Picker 의 "날짜와 함께")화면의 "다음"
달만(예산 · 홈 · 카드 실적)Input Button → 연 | 월 휠(Wheel Picker)"완료"
먼 날(몇 해 앞뒤 — 적금 만기 · 입사일)같은 달력 — 제목을 눌러 연 · 월 휠로 옮긴 뒤 날을 누른다(아래 "연 · 월 옮기기")"완료"
정해진 목록이 아닌 값(금액 · 메모)Input — 치는 칸. 날짜 · 시각은 치지 않는다(사용자 결정)—
펼친 달력(Inline)시트팝오버휠(달만 · 시각)치는 칸
보이는 자리화면 흐름 안에 늘아래에서 올라온다 · 딤칸 아래 8 · 딤 없음시트 · 팝오버 안—
여는 법열 것이 없다Input ButtonInput ButtonInput Button—
확정화면의 "다음" · "완료""완료""완료""완료"—
폭화면 폭 − 좌우 24시트 폭 − 48(360 → 312)336(두 달 696)휠 220 높이 · 5칸—
쓰는 때날짜가 그 화면의 주인공1280 미만 폼1280 이상 폼순서 있는 값 · 날은 아니다groo 는 두지 않는다
groo 지금쓰는 곳 없음(SEED 와 같게 둔다)결정결정결정결정(두지 않는다)

예외 · 주의

  • 펼친 달력은 확정 버튼이 없다 — 화면의 "다음" 이 확정이고, 고른 날은 달력 아래 한 줄로 되짚는다("2027년 3월 12일 (금)까지 · 141일 남았어요").
  • 펼친 달력도 달력 모양 · 키 · 6주 · 막힌 날은 시트 · 팝오버와 같다 — 바뀌는 것은 놓이는 자리와 확정뿐이다.
  • 폼 안에 달력을 펼쳐 두지 않는다 — 폼의 여러 칸 가운데 하나면 칸이다. 펼치면 폼이 두 배로 길어지고 다른 칸이 밀린다.
  • 먼 날짜가 잦은 칸(입사일 · 만기일)은 열 때 그 자리의 흔한 해로 시작해도 된다 — 연의 범위는 자리마다 정한다(아래 "연 · 월 옮기기").

기간 — 칸 하나, 달력 하나

기간은 시작 · 종료 두 칸으로 나누지 않는다 — 칸 하나("9월 28일~10월 6일")를 누르면 한 달력에서 시작과 끝을 고른다.

  • 첫 탭이 시작, 시작 뒤의 날을 누르면 끝 — 사이가 띠로 이어진다.
  • 시작보다 앞을 누르면 그날이 새 시작이다(둘을 바꾸지 않는다).
  • 같은 날을 두 번 누르면 하루짜리 기간이다. 하루짜리를 막아야 하는 자리는 "2일 이상" 같은 제약을 둔다.
  • 기간이 완성된 뒤 다시 누르면 새로 시작한다.
  • 끝을 고르는 동안 미리 칠해 보이지 않는다. 시작을 고르는 순간 제약에 걸린 날이 한꺼번에 막힌 날로 바뀔 수 있다 — 그런 제약(최소 · 최대 기간)은 달력 위 Callout 으로 미리 알린다.
① 첫 탭 — 시작
② 시작 뒤를 누르면 끝 — 사이가 띠로
③ 시작보다 앞을 누르면 그날이 새 시작

같은 날을 두 번 누르면 하루짜리 기간이고, 다 고른 뒤 다시 누르면 새로 시작한다. 끝을 고르는 동안 띠를 미리 칠하지 않고, 끝을 고르기 전에는 "완료" 가 막힌다.

첫 탭 시작 · 둘째 탭 끝 · 앞을 누르면 새 시작

빠른 기간

기간 달력 위에 칩 한 줄을 둔다. 누르면 그 기간을 달력에 칠하고(그 달로 옮긴다) "완료" 로 넣는다 — 하나 고르기라 고른 칩은 짙게 채워지고, 달력에서 다른 날을 누르면 칩 고름이 풀린다. 이름과 범위는 아래 한 벌이고, 화면은 이 안에서 고른다(이름이 같으면 어디서나 같은 기간이다).

이름기간(오늘이 2026년 10월 2일이면)
이번 주일요일 ~ 토요일(9월 27일 ~ 10월 3일)
이번 달1일 ~ 말일(10월 1일 ~ 31일)
지난 달지난달 1일 ~ 말일(9월 1일 ~ 30일)
최근 7일 · 30일오늘을 넣은 7일 · 30일(9월 26일 ~ 10월 2일)
최근 3개월 · 6개월 · 1년이번 달을 넣은 석 달 · 여섯 달 · 열두 달의 1일 ~ 이번 달 말일(8월 1일 ~ 10월 31일)
올해1월 1일 ~ 12월 31일

달력 단위다 — 끝은 그 단위의 마지막 날이고, 앞으로의 날(예정 거래 · 일정)도 들어간다. 주는 달력처럼 일요일부터다. 칩을 누르면 그 기간의 시작이 든 달로 옮긴다. 기간의 시작 · 끝이 고를 수 있는 범위 밖이거나 막힌 날이면 그 칩을 막는다 — 잘라서 넣지 않는다(이름이 같으면 같은 기간이어야 한다). 사이에 막힌 날이 있는 것은 괜찮다(손으로 고를 때와 같다).

9:41
가계부
9월 1일~9월 30일
기간 선택
이번 달을 눌렀다그 기간을 칠하고 그 달로 옮긴다 — 칸에는 "완료" 로 넣는다
desk.groo.app
통계
9월 1일~9월 30일
팝오버 — 넘치면 줄바꿈칩 사이 8 · 달력과 12 — 하나 고르기, 고른 칩은 짙게
기간 시트의 칩 줄 — 이번 달을 누르면 10월 전체가 칠해진다

연 · 월 옮기기

하루를 고르면 달력이 기본이다 — 요일 · 오늘과의 거리가 보인다. 몇 해 앞뒤의 먼 날도 이 길로 고른다 — 연 · 월 · 일 세 휠은 피한다(Wheel Picker 의 "휠을 쓰는 자리"). 제목을 누르면 요일 줄과 날짜 자리(요일 줄 + 6 × 칸 — 100% 336, 글이 크면 달력을 따라 늘어난다)에 연 | 월 휠이 뜬다(Wheel Picker medium · 7칸). 셰브론이 위로 돌고 이전 · 다음은 막힌다. 제목을 다시 누르면 고른 달로 옮긴다. 연의 범위는 자리마다 정하고(기본 오늘 ± 100년), 월은 돌아간다.

제목을 누르면셰브론이 위로 돌고 요일 줄 · 날짜 자리에 휠이 뜬다
연 | 월 휠Wheel Picker medium · 7칸 — 열린 동안 이전 · 다음은 막힌다. 제목을 다시 누르면 고른 달로
제목을 누르면 연 · 월 휠

고를 수 없는 날

자리마다 고를 수 있는 범위가 다르다(환불일은 거래일 ~ 오늘, 할 일 마감은 오늘부터). 그 밖의 날은 막힌 날로 그린다 — 흐린 숫자 + 취소선, 키보드 초점은 간다. 이미 확정돼 바꿀 수 없는 시작일(진행 중인 기간 늘리기)은 읽기 전용 — 채움을 남겨 흐리게 그린다. 달력 전체가 보기 전용이면 날짜마다가 아니라 달력 전체를 읽기 전용으로 둔다.

여러 날

multiple 은 누를 때마다 고르고 풀린다 — 고른 날은 따로 그린 원이고 띠로 잇지 않는다. 최대 개수가 있으면 달력 위에 남은 개수를 보이고, 다 고르면 고르지 않은 날이 막힌 날(취소선)이 된다 — 고른 날은 풀 수 있다. 칸에는 가장 이른 날 + 나머지 개수("10월 14일 (수) 외 2개" — Select 여럿 고르기와 같은 꼴). 지금 쓰는 곳은 없다.

글

칸에 들어가는 값은 International Design(v106)의 표기다 — 올해는 "10월 15일 (목)", 다른 해는 "2027년 1월 3일 (일)", 기간은 "10월 1일~10월 31일"(물결표를 앞뒤에 붙여 쓴다 — International Design, 올해가 아닌 날이 끼면 양쪽에 연도). 시트 제목은 고를 값의 종류("날짜 선택" · "기간 선택"), 칸이 비면 placeholder 도 같은 말이다.

코드

레시피 recipes/shadcn/components/ui/date-picker.tsx 를 Input Button 이 연 시트 · 팝오버 안에 둔다. 값은 쓰는 쪽이 가진다 — 달력은 고르던 값(draft)을 보이고, "완료" 가 칸에 넣는다. 여는 자리는 useInputButtonSurface()(1280 미만 "sheet" · 이상 "popover")가 정한다. 아래 미리보기는 스펙 값으로 그린 모습이다.

날짜 하나 — "완료" 로 넣는다

10월 15일 (목)

이 창의 폭으로 연다 — 1280 미만은 아래 시트, 이상은 칸 아래 팝오버.

import { CalendarDays } from "lucide-react"
import { DatePicker, formatDateValue } from "@/components/ui/date-picker"
import { InputButton, useInputButtonSurface } from "@/components/ui/input-button"

const surface = useInputButtonSurface()
const [draft, setDraft] = React.useState(date)

<InputButton value={formatDateValue(date)} placeholder="날짜 선택" suffixIcon={<CalendarDays />} onClick={() => { setDraft(date); setOpen(true) }} />

// 열면 고른 날(없으면 오늘)로 초점을 옮긴다
<DatePicker selection="single" value={draft} onValueChange={setDraft} autoFocus />
<Button disabled={!draft} onClick={() => { setDate(draft); setOpen(false) }}>완료</Button>

기간 — 칩 줄 · 이어지는 달 · 두 달

9월 1일~9월 30일

이 창의 폭으로 연다 — 1280 미만은 아래 시트, 이상은 칸 아래 팝오버. 기간은 시트에서 달이 위아래로 이어지고, 팝오버에서 두 달이 나란히 보인다.

// 이어지는 달은 시트 높이를 채운다(시트 h-[90dvh]), 두 달은 팝오버 폭 744 — PopoverContent className={DATE_PICKER_TWO_MONTHS_POPOVER}
<DatePicker
  selection="range"
  visibleRange={surface === "sheet" ? "continuous" : "twoMonths"}
  autoFocus
  presets={["thisWeek", "thisMonth", "lastMonth", "last3Months", "thisYear"]}
  value={draft}
  onValueChange={setDraft}
/>
<Button variant="neutralWeak" onClick={() => setDraft(undefined)}>초기화</Button>
<Button disabled={!draft?.end} onClick={apply}>완료</Button>

고를 수 있는 범위 — 환불일

날짜 선택
거래일 9월 24일부터 오늘까지 고를 수 있어요.
열면 — 9월 24일 앞 · 오늘 뒤는 막힌 날(흐린 숫자 + 취소선, 키보드 초점은 간다)

이 창의 폭으로 연다 — 1280 미만은 아래 시트, 이상은 칸 아래 팝오버.

<DatePicker selection="single" min={transactionDate} max={today} value={draft} onValueChange={setDraft} />

Behavior

인터랙션동작
날짜 누르기하루 — 고른다(다시 눌러도 풀리지 않는다). 기간 — 위 "기간" 의 순서. 여러 날 — 고르고 풀린다. 칸 값은 "완료" 전까지 그대로
막힌 날 · 앞뒤 달 누르기아무 일도 없다
이전 · 다음한 달씩 — 6주라 높이는 그대로
제목 누르기연 · 월 휠을 열고 닫는다. 닫으면 고른 달로 옮기고 그 달 1일이 다음 Tab 자리
빠른 기간 칩그 기간을 칠하고 그 달로 옮긴다. 달력에서 다른 날을 누르면 칩 고름이 풀린다
열 때고른 날(없으면 오늘)이 든 달 — 초점은 그 날짜로 간다(input-button.md)
이어지는 달 스크롤보이는 달이 바뀌면 그 달 1일이 다음 Tab 자리

키보드

WAI-ARIA Grid 다 — 날짜 하나만 Tab 순서에 들고 방향키로 옮긴다. 웹 · 앱이 같다 — 앱도 하드웨어 키보드 · 스위치 접근에서 아래 키를 받고, 열 때 초점은 고른 날(없으면 오늘)로 간다. 링은 키보드일 때만 그린다(2026-10-21 사용자 결정 — 03-C 4A).

키동작
← →하루 전 · 뒤
↑ ↓한 주 전 · 뒤
Home End그 주의 일요일 · 토요일
PageUp PageDown한 달 전 · 뒤(같은 날, 없으면 말일) — 두 달 보기는 두 달
Shift + PageUp PageDown한 해 전 · 뒤
Enter Space초점이 있는 날을 고른다(막힌 날은 무시)
Tab달력 밖(다음 요소 — "완료")으로

보이는 달 밖으로 옮기면 달이 따라 넘어가고 "2026년 11월" 을 읽는다(두 달 보기는 "2026년 10월~2026년 11월").

Accessibility

기준검증
WCAG 1.4.3 Color contrast(글자 ≥ 4.5:1)숫자 fg-neutral-muted 바탕 위 7.11 · 다크 6.67 · 기간 띠 위 6.58 · 5.93, 고른 날 16.41 · 13.42 ✓. 막힌 날 · 앞뒤 달은 누를 수 없는 표시라 기준 밖(막힌 날은 취소선이 함께 알린다)
WCAG 1.4.11 Non-text contrast(≥ 3:1)고른 날 짙은 원 ✓. 오늘의 옅은 원은 바탕과 1.08 · 1.13 — 그래서 숫자 굵기로도 알린다. 호버 원(투명)은 바탕과 1.15 · 1.77, 오늘 원과 1.06 · 1.57 로 갈린다. 초점 링 stroke-focus-ring ✓
WCAG 1.4.1 Use of color오늘은 굵기, 막힌 날은 취소선 — 색만으로 알리지 않는다 ✓
WCAG 2.1.1 Keyboard위 키보드 표 — 모든 날을 키로 고른다 ✓
WCAG 2.5.8 Target Size — Minimum(AA ≥ 24×24)날짜 칸 44.6 × 48(360 화면) · 48 × 48(팝오버) ✓ · 이전 · 다음 40(누르는 영역 44) ✓
WCAG 2.5.5 Target Size — Enhanced(AAA ≥ 44×44)날짜 칸 ✓(320 화면은 38.9 × 48 ⚠) · 이전 · 다음 44 ✓
WCAG 4.1.3 Status messages보이는 달이 바뀌면 aria-live="polite" 로 "2026년 11월" 을 읽는다 ✓
앱(Flutter 3.44.9)표 · 줄 · 칸 · 열 머리 역할(table · row · cell · columnHeader)은 의미 트리에 두지만 Android · iOS 화면 읽기에는 전달되지 않는다(Flutter 가 역할을 버린다) — 날짜 칸은 이름("2026년 10월 15일 목요일" + ", 오늘") · 고름 상태로 알리고 그것으로 충분하다. 연 · 월 휠 칼럼은 Wheel Picker 의 앱 줄대로 spinbutton 역할 대신 이름 + 값 + 올리기 · 내리기(조절 가능)다
ARIA달력 role="group" 이름 "날짜 선택"(또는 칸 라벨), 달마다 role="grid" + 제목으로 aria-labelledby, 기간 · 여러 날은 aria-multiselectable. 요일은 columnheader(이름 "일요일"). 날짜 버튼 이름 "2026년 10월 15일 목요일", 오늘 aria-current="date", 고른 날 · 기간 사이 칸 aria-selected, 막힌 날 · 읽기 전용 aria-disabled(읽기 전용은 이름 끝에 ", 읽기 전용 시작일"). 앞뒤 달은 숫자만 aria-hidden(칸은 남겨 요일 짝을 지킨다). 이전 · 다음 이름 "이전 달" · "다음 달", 제목 버튼 aria-expanded. 이름은 한국어 · 영어 두 벌(앱 언어를 따른다)

Do / Don't

✅ Do

  • 날짜 칸을 누르면 달력이 열리게 — 날짜를 치게 하지 않는다.
  • 기간은 칸 하나에 "9월 28일~10월 6일", 달력 하나에서 시작 · 끝을 고른다.
  • 최소 · 최대 기간 같은 제약은 고르기 전에 Callout 으로 알린다.
  • 빠른 기간은 정해진 이름 · 범위 한 벌에서 고른다.

❌ Don't

  • 날짜 칸을 치는 칸으로 두기(지금 세 제품 66곳).
  • 고른 날 · 오늘을 브랜드 색으로 채우기 — 고른 날은 짙은 회색, 오늘은 옅은 원 + 굵기.
  • 막힌 날을 흐림(불투명도)으로만 그리기 — 흐린 색 + 취소선.
  • 같은 "이번 달" 을 화면마다 다른 기간으로 쓰기.
  • 날짜를 누르는 순간 칸에 넣고 닫기 — "완료" 로 넣는다.

Specification

Base

부위상태속성값
rootenabled너비width336px팝오버 — 칸 48 × 7. 시트는 시트 폭 − 좌우 24 · 24(360 화면 312 · 칸 44.6)
배경backgroundbg-layer-floating#FFFFFF다크 #2D3346
presetsenabled아래 여백paddingBottomspacing-x312px칩 줄 ↔ 머리 12
간격gapspacing-between-chips8px칩 사이 8 — 시트는 한 줄 가로 스크롤(화면 끝까지), 팝오버는 줄바꿈
칩chipChip outlineStrong medium 36하나 고르기(라디오) — 고른 칩은 짙은 채움, 달력에서 다른 날을 누르면 풀린다. 이름 · 범위는 date-picker.md 의 '빠른 기간'
headerenabled높이height48px최소 — 글자가 크면 그만큼만 늘어난다. 칸 · 머리 · 요일 줄 · 원 · 이전 · 다음은 px, 글자만 배율(SEED, 03-C 1B)
titleenabled좌우 여백paddingXspacing-x14px제목 글자는 머리 왼쪽에서 4 — 누르는 자리는 머리 높이 48 전체
간격gapspacing-x14px글자 ↔ 셰브론
모서리radiusradius-r28px바탕이 없어 초점 링에만 보인다
글자·아이콘foregroundfg-neutral#1A1F2E다크 #F5F6FA
글자typographytext-t516px / 22px
굵기fontWeight700
titleIconenabled크기size20pxlucide chevron-down
색colorfg-neutral#1A1F2E다크 #F5F6FA
navButtonenabled크기size40pxButton ghost iconOnly medium 을 px 로 — 글자 크기를 따르지 않는다(03-C 1B). 둘 사이 0, 머리 오른쪽 끝, 누르는 영역 44
아이콘 크기iconSize18pxlucide chevron-left · chevron-right
색colorfg-neutral#1A1F2E다크 #F5F6FA
weekdayenabled높이height48px최소 — 글자가 크면 그만큼만 늘어난다(03-C 1B)
글자·아이콘foregroundfg-neutral-subtle#62697A다크 #A2A8B7
글자typographytext-t414px / 19px
굵기fontWeight500
cellenabled높이height48px최소(SEED dateCell minHeight) — 글자가 크면 그만큼만 늘어난다(03-C 1B): max(48, 숫자 줄 높이 + 위아래 3 · 3) — 날짜 버튼 · 앞뒤 달 숫자가 위아래 3 을 가진다(200% 44 + 6 = 50 · 달력 396). 폭은 달력 폭 ÷ 7 — 칸 전체가 누르는 자리, 칸 사이 0
커서cursorpointer
주 수weeks6늘 6주 — 달을 넘겨도 머리 · 바닥이 움직이지 않는다(이어지는 달만 그 달의 주 수)
dayVisualenabled크기size42pxpx — 글자 크기를 따르지 않는다(03-C 1B, SEED). 칸 위 3 · 가로 가운데 — 원 · 띠끼리 6 떨어진다. 칸이 44 보다 좁으면(320 화면) 칸 폭 − 2
모서리radiusradius-full9999px(알약)
배경backgroundtransparent
전환 대상transitionPropertybackground-color
전환 시간transitionDurationmotion-duration-color-transition150ms
전환 곡선transitionEasingmotion-ease-easingcubic-bezier(0.35, 0, 0.35, 1)
dayLabelenabled글자·아이콘foregroundfg-neutral-muted#535866다크 #B7BDCC
글자typographytext-t516px / 22px숫자 폭을 같게(tabular-nums)
굵기fontWeight500
rangeBandenabled높이height42px칸 위 3 — 원과 같은 높이(칸이 좁아 원이 줄면 띠도 같이). 시작 칸은 원 가운데부터 오른쪽, 끝 칸은 왼쪽부터 원 가운데까지, 사이 칸은 칸 폭 전체 — 줄 끝에서 둥글리지 않고 칸 끝에서 끊는다
배경backgroundbg-neutral-weak#F5F6FA다크 #353B4D
monthLabelenabled높이height48px최소 — 글자가 크면 그만큼만 늘어난다(03-C 1B)
글자·아이콘foregroundfg-neutral#1A1F2E다크 #F5F6FA
글자typographytext-t516px / 22px
굵기fontWeight700
wheelenabled높이height336px요일 줄 + 6주 자리를 덮는다 — 높이는 요일 줄 + 6 × 칸이라 글이 크면 달력을 따라 늘어난다(100% 요일 줄 48 + 6주 288 · 200% 48 + 50 × 6 → 348, 열고 닫아도 달력 높이가 그대로). Wheel Picker medium 44 × 7 = 308 을 가운데에(100% 위아래 14). 열린 동안 이전 · 다음은 막힌다
칼럼columns연 120 · 월 96연은 오른쪽 · 월은 왼쪽 정렬로 가운데에 모은다(SEED 와 같다) — 항목은 "2026년" · "10월"
배경backgroundbg-layer-floating#FFFFFF다크 #2D3346
footerenabled위 여백paddingTopspacing-x416px팝오버 — 달력 아래 16, 버튼 small 36 오른쪽 맞춤. 시트는 Bottom Sheet 바닥(위 12 · 아래 16, large 48 — 하나면 폭 전체, 둘이면 반씩)
dayVisualhovered배경backgroundbg-neutral-weak-alpha-pressed#00000010다크 #FFFFFF2ESEED 투명 색 — 바탕 1.15 · 다크 1.77(2026-10-21 03-C 2B). 마우스(고운 포인터)만 — 축소 없음. 오늘(옅은 원) · 기간 사이 날(띠) 위에서는 불투명 bg-neutral-weak-pressed(투명 색을 띠에 얹으면 또 다른 색이 된다). 막힌 날 · 읽기 전용 · 앞뒤 달에는 없다
dayVisualpressed배경backgroundbg-neutral-weak-alpha-pressed#00000010다크 #FFFFFF2E터치는 누르는 동안 — 오늘 · 기간 사이 날 위에서는 불투명 bg-neutral-weak-pressed. 날짜는 줄지 않는다(이전 · 다음은 Button 처럼 2px 축소)
focusRingfocused링 두께width2px
링 색colorstroke-focus-ringDesk#0147AD다크 #7AA9F6HR#075B3C다크 #2ABE84
링 간격offset-2px원 자리(42) 안쪽 — 칸이 아니라 원 둘레
dayVisualtoday배경backgroundbg-neutral-weak#F5F6FA다크 #353B4D
dayLabeltoday글자·아이콘foregroundfg-neutral#1A1F2E다크 #F5F6FA
굵기fontWeight700색이 아니라 굵기로도 알린다 — 고른 날 · 기간 안에서도 굵기는 남는다
dayVisualselected배경backgroundbg-neutral-inverted#1A1F2E다크 #F5F6FA하루 · 여러 날의 고른 날, 기간의 시작 · 끝 — 오늘이어도 이 모양이 이긴다(굵기는 남는다)
dayLabelselected글자·아이콘foregroundfg-neutral-inverted#FFFFFF다크 #242938
dayVisualinRange배경backgroundtransparent띠가 바탕 — 오늘이어도 원은 그리지 않는다(굵기만 남는다)
dayLabelinRange글자·아이콘foregroundfg-neutral-muted#535866다크 #B7BDCC
celloutside커서cursordefault
dayLabeloutside글자·아이콘foregroundfg-disabled#8A91A0다크 #838997앞뒤 달 날짜 — 보이기만 하고 누르지 못한다(숫자만 보조 기술에 숨기고 칸은 남겨 요일 짝을 지킨다). 기간 띠도 그리지 않는다. 다른 달은 이전 · 다음 · 화살표 키로
celldisabled커서cursornot-allowed
dayLabeldisabled글자·아이콘foregroundfg-disabled#8A91A0다크 #838997
취소선textDecorationline-through고를 수 없는 날 — 흐린 색과 함께 취소선. aria-disabled 라 키보드 초점은 간다
cellreadOnly커서cursordefault
dayVisualreadOnly배경backgroundstroke-neutral-solid#767C8B다크 #838997확정된 시작일 — 채움은 남기고 톤을 낮춘다(SEED palette gray-600 의 역할 짝). 누르지 못하지만 초점은 간다
dayLabelreadOnly글자·아이콘foregroundfg-neutral-inverted#FFFFFF다크 #242938

visibleRange=twoMonths

부위상태속성값
rootenabled너비width696px336 + 24 + 336 — 팝오버 폭 744(Popover 최대 480 의 예외)
칸 간격columnGapspacing-x624px두 달 사이 24
headerenabled높이height48px머리를 나누지 않는다 — 달 이름은 달마다 가운데, 이전 버튼은 첫 달 왼쪽 끝 · 다음 버튼은 둘째 달 오른쪽 끝(위 4)
titleenabled글자typographytext-t516px / 22px달 이름은 누르지 않는다 — 연 · 월 휠이 없다

visibleRange=continuous

부위상태속성값
rootenabled높이height시트에 맞춘다시트를 화면 높이의 90% 로 열고 머리 · 칩 줄 · 바닥을 뺀 높이 — 그 안에서 달이 위아래로 이어진다(스크롤바 숨김)
headerenabled높이height0px머리 없음 — 스크롤이 달을 넘긴다. 연 · 월 휠도 없다
weekdayenabled자리positionsticky맨 위에 붙는다 — 달마다의 요일 줄은 없다
cellenabled주 수weeks그 달의 주 수4 ~ 6 — 앞뒤 달 날짜는 비운다(달이 이어져 다음 달이 바로 아래에 있다)
monthLabelenabled좌우 여백paddingXspacing-x14px왼쪽 정렬, 달 아래 16
fogenabled높이height96px아래 끝 — 투명에서 바탕색으로

SEED 와 다른 점

  • 오늘은 옅은 원 + 숫자 700 — groo 옅은 원(bg-neutral-weak)은 바탕과 1.08:1 이라 굵기로도 알린다. 기간 안 · 고른 날이어도 굵기는 남는다(SEED 는 옅은 원만, 기간 안에서는 사라진다).
  • 앞뒤 달을 흐리게 채우고 늘 6주 — SEED 는 비우고 4 ~ 6주라 달을 넘길 때 시트 머리 · 바닥이 48 · 96 씩 움직인다. 흐린 날은 누르지 못하고 보조 기술에 숨긴다.
  • 팝오버 달력 336(칸 48 × 7) · 두 달 696 — SEED 는 부모 폭.
  • 좁은 칸에서 원을 줄인다 — 칸이 44 보다 좁으면 원은 칸 폭 − 2(SEED 는 320 화면에서 이웃 원이 겹친다).
  • 색은 groo 역할 짝 — 고른 날 bg-neutral-inverted, 읽기 전용 시작일 stroke-neutral-solid(SEED palette gray-600), 기간 사이 숫자 fg-neutral-muted(SEED 코드와 같다 — 그림은 fg-neutral).
  • 호버 · 누름은 SEED 와 같은 투명 색(bg-neutral-weak-alpha-pressed) — 오늘 · 기간 사이 날 위만 불투명 bg-neutral-weak-pressed 다(투명 색을 띠에 얹으면 또 다른 색이 된다).
  • 빠른 기간 칩 줄 — SEED 에는 가이드가 없다("오늘로 이동" 예제뿐).
  • Week 보기는 두지 않는다 — 쓰는 곳이 없다.
  • 펼친 달력(Inline)은 SEED 와 같게 둔다 — 지금 쓰는 곳은 없다 — multiple 과 같은 결이다(2026-10-22 1C).
  • 열 때 초점은 고른 날(없으면 오늘) — SEED 는 정하지 않았다(Tab 자리는 고른 날, 없으면 1일).

Migration notes

2026-10-22 — 어디에 놓나(펼친 달력) · 먼 날은 달력 제목

SEED Date Picker 의 Layout 셋(Inline · Sheet · Popover) 가운데 Inline 만 스펙에 없었다 — 10-01 · 10-03 비교 페이지에 오른 적이 없어 거절이 아니라 빠짐이다. "어디에 놓나" 상황 표 · 견주기 표에 펼친 달력을 넣고 "지금 쓰는 곳은 없다" 를 함께 적었다(1C — 10-03 12 에서 쓰는 곳 없는 multiple · 읽기 전용도 "SEED 와 같게 둔다" 를 골랐다). 날짜 + 시각은 결정(두 칸 나란히) 그대로 + "날짜가 주된 단계면 달력은 펼치고 시각은 칸"(2B — Time Picker). 하루는 달력이 기본, 먼 날은 제목의 연 · 월 휠, 연 · 월 · 일 세 휠은 "피한다"(3B — Wheel Picker). 사용자 결정 — https://claude.ai/artifact/Mag1tEv51MdQHdy1o8hY3L. 고르지 않은 안: 말 없음(1A) · 두지 않는다고 적기(1B) · 결정 문장만(2A) · 세 휠 Don't 그대로(3A) · 먼 날 칸은 세 휠 허용(3C). 값 변경 없음. 웹 · 앱 할 일 없음 — 펼친 달력을 쓰는 화면이 생기면 그 화면이 시트 없이 달력을 놓는다.

2026-10-22 — 큰 글자 칸 · 휠 자리 · 앱 접근성(I-04 검수)

  • 큰 글자 칸 — 사용자가 본 그림(1B — 칸 = max(48, 줄 높이 + 6), 200% 396)을 레시피가 만들지 못했다: 칸 min-h-[48px] 에 날짜 버튼 p-0 이라 200% 에서 칸 48 · 달력 384 였다. 레시피 날짜 버튼(DAY)과 앞뒤 달 숫자(OUTSIDE)에 위아래 3(py-[3px])을 두고, 이어지는 달은 이름 줄 · 칸 · 요일 줄을 숨은 견본으로 재서 달 높이를 셈한다(배율이 바뀌면 다시 재고 보던 달로). 100% 값은 그대로다. 웹은 레시피 그대로 따라 고친다(date-picker-variants DAY · OUTSIDE · 이어지는 달 높이 셈). 앱은 이미 이 셈이다.
  • 휠 자리 — wheel.height 336 고정을 "요일 줄 + 6 × 칸"(100% 336 · 200% 348)으로. 레시피 WHEEL 높이는 calc(max(48px, var(--text-t4--line-height)) + 6 * max(48px, calc(var(--text-t5--line-height) + 6px))) 다. 앱은 이미 이렇다(웹 · 레시피 336 고정이 200% 에서 휠을 열 때 달력을 12 줄였다).
  • 앱 접근성 — Flutter 3.44.9 는 spinButton 역할을 구현하지 않았고(디버그에서 오류), 표 · 칸 역할을 Android · iOS 에 전달하지 않는다. 휠은 이름 + 값 + 올리기 · 내리기, 날짜 칸은 이름으로 알린다(Accessibility 의 앱 줄).

2026-10-21 — 큰 글자 · 호버 · 앱 키 · 캘린더 화면(03-C)

구현 조사 03-C(2026-10-16 ~ 17)를 보고 사용자가 정했다(비교 페이지 https://claude.ai/artifact/3nWUZCYpPh2Cg3uXc3DKtp).

  • 큰 글자(1B) — 글자만 배율, 칸 · 머리 · 요일 줄은 최소 48 · 원 42 · 이전 · 다음 40 은 px(SEED). 웹은 rem 이던 칸이 200% 에서 96 으로 커져 시트를 넘고 제목이 "202…" 로 잘렸다 — 레시피 min-h-[48px] · 이전 · 다음 h-[40px] w-[40px]. 앱은 칸 48 고정을 최소 48 로. 거절: 웹 rem 그대로 · 달력 글자 모두 -static.
  • 호버 · 누름 원(2B) — 불투명 bg-layer-floating-pressed 가 다크에서 오늘 원(bg-neutral-weak)과 같은 색이었다. SEED 투명 색 bg-neutral-weak-alpha-pressed 로(추천 A "늘 bg-neutral-weak-pressed" 가 아니다). 오늘 · 기간 위는 그대로 불투명 bg-neutral-weak-pressed.
  • 앱 방향키(4A) — 앱도 웹과 같은 키 · 열 때 초점 · 키보드일 때만 링. 앱 PDatePicker 에 Focus · 키 처리와 테스트를 더한다(이어지는 달은 스크롤 위치를 따라간다).
  • 캘린더 화면 격자(5A) — 피커가 아니지만 같은 규칙을 쓴다: 이웃 달 날짜는 숫자만 fg-disabled(일정 · 금액은 이번 달과 같게 읽힌다), 꺼진 캘린더 줄은 체크로만 알리고 흐리게 하지 않는다(불투명도 금지 — DESIGN State). 웹 calendar-month-view.tsx:206 · 233 · 252 · calendar-source-toggle.tsx:138 · 169 의 불투명도를 걷는다.

2026-10-03 — SEED Date Picker 로 새로 둔다(옛 Calendar 를 대신)

사용자가 비교 페이지에서 정했다 — 달력 모양 SEED(칸 48 · 원 42 · 숫자 16), 오늘은 옅은 원 + 굵기, 앞뒤 달은 흐리게 채우고 6주(누르지 못함), 연 · 월 휠, 기간은 달력 하나(시트 이어지는 달 · 팝오버 두 달), 빠른 기간 칩 한 벌(달력 단위), 여러 날 · 읽기 전용도 둔다. 옛 Calendar(react-day-picker · 원 40 · 고른 날 브랜드 채움 · 오늘 2px 테두리 · 앞뒤 달 tertiary · 막힌 날 불투명도 0.5)는 걷었다 — 옛 스펙은 calendar.history/v-pre-seed-date.*.

제품은 앱 적용 단계에서 옮긴다(2026-10-02 조사 — Desk 웹 · HR 은 크로미움에 띄워 쟀고, Desk 앱은 위젯 테스트로 쟀다).

  • 세 제품 모두 — 날짜 칸이 치는 칸이다(Desk 웹 14 · 앱 19 · HR 19, 네이티브 date 6 따로). 달력은 누르면 바로 들어가고 닫힌다. 기간 달력은 한 곳도 없다(두 칸).
  • Desk 웹 — 앞뒤 달이 이번 달과 같은 색, 다크에서 고른 날 · 오늘 테두리 1.96:1, 이름이 영어("Go to the Previous Month" · "Today, …"), 월 셀렉트가 브라우저 언어(Jan…Dec), 폰에서도 팝오버(시트 위로 뜬다), 빠른 기간 세 벌이 같은 이름에 다른 기간.
  • Desk 앱 — 다크에서 고른 날 2.75:1, 낭독기에 날짜가 "8" 로만 읽힌다(버튼 아님 · 이전 · 다음 이름 없음), 날짜 상한이 2030-01-01(일정 · 할 일 · 저축 · 더치페이)로 박혀 있다, 일정 화면이 2020 ~ 2030 밖에서 깨진다.
  • HR 웹 — 칸에 치면 값이 깨진다("2" → "2001-02-01", 업무 보고 필터는 지울 수 없다, 일정 종료일은 칠 때마다 토스트), 한국어 화면에 영어 달력, 오늘 회색 사각 1.06:1, UTC 로 읽어 하루 전을 칠한다.
  • 앱 적용 때 화면마다 정할 자리 — 자리별 고를 수 있는 범위(거래 · 일정의 미래, 할 일 · 저축 상한), HR 보기용 작은 달력(일 보기 옆 · 근무 미입력 위젯), 일정 화면 격자(피커가 아니다 — 오늘 = 채운 원은 캘린더 화면 차례에), 통계의 월 · 분기 · 년 보기.

이 페이지