Pickers (date + time)
components specs/components/pickers.kmd
Compound controls for selecting a date, time, date range, or date-time. Material parity (`/components/date-pickers` and `/components/time-pickers`). Covers docked vs modal date pickers, dial vs input time pickers, date ranges, locale rules, and keyboard navigation.
Quando esta spec se aplica
Triggers primários
- Add a date picker
- Add a time picker
Todos os triggers
- Let user pick a date
- Let user pick a time
- Pick a date range
- Replace native date input with branded picker
Corpo da especificação
Spec — Pickers (date + time)
Facet Visual of Koder Design. Material parity: https://m3.material.io/components/date-pickers and https://m3.material.io/components/time-pickers.
Variant matrix
| Picker | Modes | Use |
|---|---|---|
| Date — modal | Calendar grid, dialog | Default for date selection |
| Date — modal input | Text input within dialog | Power-user keyboard entry |
| Date — docked | Calendar attached to anchor input | Continuous form context |
| Date range — modal | Two-month calendar with range selection | Trip / report range |
| Time — dial | Analog clock face | Default mobile entry |
| Time — input | Two numeric fields HH:MM | Desktop / keyboard preference |
R1 — Date picker — modal (calendar)
Anatomy:
┌──────────────────────────────────────┐
│ Select date ⌄ ⌃ Year │
│ ──────────────────────────────────── │
│ ◂ May 2026 ▸ │
│ │
│ S M T W T F S │
│ 1 2 │
│ 3 4 5 6 7 8 9 │
│ 10 11 12 13 14 15 16 │
│ 17 18 19 20 21 22 23 │
│ 24 25 26 27 28 29 30 │
│ 31 │
│ │
│ [Cancel] [OK] │
└──────────────────────────────────────┘
- Container: dialog, 360 dp wide (mobile portrait) / 328 dp (desktop)
- Header: shows current selection in
headline-small - Month navigation: arrows + month name; tap month opens year picker
- Day grid: 7 columns, 6 rows max; current day with circle outline; selected day with filled circle (accent color)
- Footer: Cancel + OK text buttons
- Today indicator: 1 px circle outline on today's date
- Selected: filled circle,
primarybg,on-primarytext
R2 — Date picker — docked
Calendar floats below an anchor text field (no modal scrim). Used in forms with multiple date fields, where modal context-switch is heavy.
- Anchor: text field with calendar icon trailing
- On focus / icon tap: calendar appears below (above if no room)
- Closes when user picks a date OR clicks outside
- No scrim — page stays interactive
R3 — Date range picker
Two-month side-by-side calendar:
┌──────────────────────────────────────────────────────┐
│ Start date → End date │
│ Mar 12 → Mar 28 │
│ ──────────────────────────────────────────────────── │
│ ◂ March 2026 April 2026 ▸ │
│ │
│ S M T W T F S S M T W T F S │
│ ... ... │
│ │
│ [Cancel] [Save] │
└──────────────────────────────────────────────────────┘
- Two months visible; tap-and-drag OR two-tap to define range
- Selected range: tonal bg (
secondary-container) for days in range; filled circle on start + end - Mobile (Compact): one month with scroll, range still applies
R4 — Time picker — dial
Anatomy:
┌───────────────────────────────┐
│ Select time │
│ ───────────────────────────── │
│ ┌─ 10 : 30 ─┐ AM PM │
│ └───────────┘ │
│ │
│ ╭─────╮ │
│ 11 │ ● 12 │
│ 10 ╱│ ╲ 1 │
│ 9 │ ● │ 2 │
│ ╲│ │ │
│ 8 └─────┘ 3 │
│ 7 6 5 4 │
│ │
│ [Cancel] [OK] │
└───────────────────────────────┘
- Display: HH : MM in large text; tap each segment to edit
- Dial: hour ring (12 positions) or minute ring (60 positions, shown as 12 multiples of 5)
- AM / PM segmented button (12-hour locale only)
- Switch to keyboard: small icon toggles to Input variant
R5 — Time picker — input
Two text fields for HH and MM with : separator, plus AM/PM segmented
button (12-hour locale only).
- Each field:
numerickeyboard on mobile; type-to-edit on desktop - Auto-advance: typing 2 digits in HH jumps to MM field
- Validation: HH ∈ [0, 23] or [1, 12]; MM ∈ [0, 59]
- Smaller dialog than dial variant (no clock face)
Used as default on desktop AND as toggle from dial when user prefers keyboard.
R6 — Locale rules
Pickers ALWAYS respect locale (per i18n/contract.kmd):
| Locale aspect | Driven by |
|---|---|
| First day of week | Locale (Sun / Mon / Sat) |
| Month / weekday names | Locale |
| Date format in header | Locale |
| 12 / 24-hour | Locale (en-US 12h; pt-BR 24h) |
| Number system | Locale (Latin / Arabic-Indic / etc.) |
Override via prop only if domain requires (e.g., 24-hour for medical schedules in en-US). Document why.
R7 — Constraints
Pickers support:
min/maxdates → out-of-range days disabled (38% opacity, not selectable)disabledDatesarray → specific dates blocked (holidays, booked slots)disabledRangesfor date range picker
Disabled dates are still navigable via keyboard but cannot be selected; screen reader announces "Disabled".
R8 — Keyboard
| Key | Date picker | Time picker |
|---|---|---|
| Tab | Enters → cycles through controls | Same |
| Arrow Up/Down | Previous/next week | Increment by 1 |
| Arrow Left/Right | Previous/next day | Switch HH ↔ MM |
| Page Up/Down | Previous/next month | Increment by 5 (minute) / 1 (hour) |
| Home / End | Start/end of week | n/a |
| Enter | Selects date / time | Selects |
| Esc | Cancels | Cancels |
R9 — Accessibility
- Dialog wrapper:
role="dialog"+aria-modal="true"+aria-labelledby(pointing to "Select date") - Calendar grid:
role="grid"+aria-label="Date picker"; each cellrole="gridcell"witharia-selectedon current - Out-of-range / disabled cells:
aria-disabled="true" - Today cell:
aria-current="date" - Time dial:
role="slider"per ring (hour / minute) witharia-valuenow / valuemin / valuemax - Time input fields: native
<input type="number">semantics; labels read "Hour" / "Minute" - Screen reader announces selection: "Selected: Monday, May 11, 2026"
R10 — Animation
- Modal open: scale-in 0.95 → 1 + fade (motion-medium)
- Month change: slide horizontal (motion-medium)
- Year picker: vertical scroll list (in-place, no slide)
- Dial click: hand rotates to target position (motion-emphasized-decelerate)
- Range drag: tonal fill grows in real-time
- Reduced motion: instant transitions; no rotation animation (snap dial)
R11 — Per-preset variation
| Preset | Date visual | Time visual |
|---|---|---|
material3 | Tonal selection, rounded buttons | Dial first, input toggle |
material2 | Solid accent selection | Dial first, no input toggle |
ios_cupertino | Wheel pickers stacked (year/month/day) | Wheel pickers (HH/MM) |
gnome | Adwaita calendar w/ accent today | Spin buttons for HH/MM |
windows_11 | Combo button revealing flyout | Combo button revealing flyout |
brutalist | Sharp grid, no animation | Sharp dial, no rotation |
terminal_classic | Text prompt YYYY-MM-DD> | Text prompt HH:MM> |
R12 — Density
| Density | Cell size | Footer height |
|---|---|---|
| Compact | 36 px | 48 px |
| Default | 40 px | 52 px |
| Comfortable | 48 px | 64 px |
R13 — Forbidden patterns
- ❌ Date picker without
min/maxfor time-bounded contexts (birthdate, expiry, etc.) - ❌ Time picker dial < 240 dp diameter (touch targets too small)
- ❌ Ignoring locale first-day-of-week
- ❌ Picker that requires server roundtrip per month change (latency)
- ❌ Picker without keyboard fallback (Input variant always available for accessibility)
- ❌ Calendar grid that scrolls vertically through years (use year picker overlay instead)
- ❌ Disabled dates without explanation (provide tooltip or description)
- ❌ Range picker that allows end < start without auto-swap
Cross-link
i18n/contract.kmd— locale-aware formattingthemes/color-roles.kmd—primaryfor selected,secondary-containerfor rangethemes/typography.kmd—headline-smallfor header,body-largefor cellscomponents/text-fields.kmd— anchor for docked variantcomponents/dialogs.kmd— modal wrapper patterninteraction/states.kmd— disabled / selected layersfoundations/elements.kmd— Control + Container families
Referências
specs/foundations/elements.kmdspecs/themes/color-roles.kmdspecs/themes/typography.kmdspecs/components/text-fields.kmdspecs/components/dialogs.kmdspecs/i18n/contract.kmd