Components · Forms & selection
Date range picker
The date picker extended to a span. The two endpoints fill Primary and square off toward the middle; the days between carry a Primary-bg tint, so the selected range reads as one continuous band.
Preview
→
June 2026
S
M
T
W
T
F
S
Build with the skill
No package to install — hand this to your AI to generate or migrate the component in your stack.
Apply the Zetta "Date range picker" component to this project using the zetta-design-md skill.
WHEN TO USE
- Migrating or fixing existing code (the common case): audit the current implementation against the `date-range-picker` spec (variants: range-start, in-range, range-end) and CORRECT every deviation — replace off-spec values, don't only add new ones.
- New component: build it to the `date-range-picker` spec in this project's stack.
AUDIT & FIX (when the component already exists)
Compare it to the skill's spec and fix, don't just append: hardcoded colors/hex, off-scale radius, wrong fonts, dark/navy fills, shadows used in place of borders (or missing borders), brand lime used as a CTA or interaction (must be primary indigo), and any missing or wrong hover / focus / active / disabled / invalid state or missing 2px focus ring. Replace each with the correct Zetta token.
ALWAYS
- Pull the authoritative spec and tokens from the skill — never guess or hardcode values.
- Use this project's own component conventions and framework idioms.
- Honor the Zetta guardrails (brand = identity only, primary = interaction, shadows for overlays) and verify in Light, Dark, and Accessibility. Anatomy & rules
[ 2024-01-10 📅 ] → [ 2024-01-20 📅 ] ← two trigger inputs
┌──────────────────┐ ┌──────────────────┐
│ < January 2024 >│ │ < February 2024>│
│ ... [10]━━━━━━━━━━━━━━━━━━━━━[20] ... │ ← range highlight
└──────────────────┘ └──────────────────┘
Range visual tokens:
date-range-day-range-start—{colors.primary}fill, left-roundeddate-range-day-in-range—{colors.primary-bg}flat band,borderRadius: 0date-range-day-range-end—{colors.primary}fill, right-roundeddate-range-day-hover-preview—{colors.primary-bg}flat band, live preview before second click
| State | Visual |
|---|---|
| Default (empty) | Both inputs show placeholder |
| Selecting start | Start input focused, calendar open, end input unfocused |
| Start selected | Start date filled, end input auto-focused |
| Range complete | Both dates filled, range highlighted on calendar |
| Hover over range | Days in range show {colors.primary-bg} highlight |
| Invalid range | End before start — error state on end input |
| Disabled | Both inputs disabled |
| Error | One or both inputs show {colors.danger} border |
When to use
- Filtering data by a date range (reports, dashboards, exports).
- Booking or scheduling with a start and end date.
When not to use
- Single date selection — use Date Picker.
- When the range is always a fixed duration (e.g. always 7 days) — use a single date picker and derive the end date.
Do
- Offer preset range options (Last 7 days, Last 30 days, This month) for common selections.
- On mobile, stack the two calendars vertically and allow swipe-based month navigation.
Don't
- Don't require the user to select dates in strict start-then-end order — swap automatically if they click end before start.
- Labels: "Start date" and "End date" — never "From" / "To" alone.
- Separator: "–" (en dash) between dates when displayed inline: "25 Jun – 30 Jun 2026".
- Error: "End date must be after start date." Specific, not "Invalid range."
- Empty state placeholder: match format to locale input expectation.
Keyboard
| Key | Behavior |
|---|---|
Tab |
Move focus to start date input, then end date input; within the calendar, move between the two grids |
Enter / Space |
Open the calendar panel for the focused input |
Arrow keys |
Navigate calendar grid |
Enter |
Select the focused date as the range start or end |
Escape |
Close calendar without selecting |
Accessibility
- All base calendar accessibility rules apply — see Date Picker.
- Announce range selection status on each date selection: "Start date selected: January 10. Now select an end date."
Spec
Values and token references resolved straight from the Zetta spec.
date-range-day-in-range
- backgroundColor
- {colors.primary-bg}
- borderRadius
- 0
date-range-day-range-start
- backgroundColor
- {colors.primary}
- textColor
- {colors.primary-text}
- borderRadius
- {rounded.base} 0 0 {rounded.base}
date-range-day-range-end
- backgroundColor
- {colors.primary}
- textColor
- {colors.primary-text}
- borderRadius
- 0 {rounded.base} {rounded.base} 0
date-range-day-hover-preview
- backgroundColor
- {colors.primary-bg}
- borderRadius
- 0
Known gaps
- Invalid range error state (range passes through disabled day) — visual treatment not yet specified.
- Preset range panel layout — not yet specified as a token variant.
- Mobile single-grid swipe navigation — not yet specified.