Calendar and Date Picker
Use calendar and date picker with the current published Askr packages.
@askrjs/themes/calendar0.0.13@askrjs/themes/date-picker0.0.13
How to use calendar and date picker
Calendar and Date Picker should use the standard themed surface unless the application is deliberately implementing its own design system on top of @askrjs/ui.
- Import the themed component from @askrjs/themes/components; use @askrjs/ui directly only when building a custom visual system.
- Keep calendar and date picker labels, state, and application actions visible at the call site instead of styling internal DOM nodes.
- Verify keyboard behavior, focus movement or return, disabled state, and both standard themes.
import { DatePicker, DatePickerInput } from '@askrjs/themes/components';
<DatePicker value={dueDate()} onValueChange={dueDate.set}>
<DatePickerInput aria-label="Project due date" />
</DatePicker>Purpose
Calendar renders the visual grid of a month view and Date Picker renders a date input — both are presentation-only wrappers from @askrjs/themes, with no @askrjs/ui headless calendar or date-picker primitive backing them. There's no month math, no range-selection logic, and no popover wiring built in; you get markup and ARIA roles for a date grid, and you supply the state.
Install and import
Import `Calendar`, `CalendarHeader`, `CalendarCaption`, `CalendarNav`, `CalendarPreviousButton`, `CalendarNextButton`, `CalendarGrid`, `CalendarHead`, `CalendarBody`, `CalendarRow`, `CalendarCell`, and `CalendarDay` from `@askrjs/themes/calendar`. `DatePicker` and `DatePickerInput` come from `@askrjs/themes/date-picker`. Both subpaths compile to the same shared components barrel as the rest of the catalog, so treat the subpath as documentation of intent rather than a separate bundle.
Live examples
A working calendar means computing the days for the visible month yourself — leading and trailing days from adjacent months, which cells are `today`, `selected`, or part of a range — and passing the right booleans to `CalendarDay` on every render. Date Picker's baseline example is simpler: `DatePickerInput` defaults to `type="date"`, so a plain native date input with no extra JavaScript is a legitimate example on its own.
Anatomy
The calendar grid nests `CalendarGrid` (`role="grid"`) containing `CalendarHead` (`role="row"`) for weekday labels and `CalendarBody` holding `CalendarRow` (`role="row"`) elements of `CalendarCell` (`role="gridcell"`) wrapping `CalendarDay` buttons. `CalendarHeader` holds `CalendarCaption`, the month/year label, and `CalendarNav` with `CalendarPreviousButton` and `CalendarNextButton`. `DatePicker` is just an outer slot around `DatePickerInput`, which renders a real `<input>`.
State model
None of it is tracked internally. `CalendarDay` takes `disabled`, `outside`, `rangeStart`, `rangeMiddle`, `rangeEnd`, `selected`, and `today` as plain booleans that it turns into matching `aria-*` and `data-*` attributes — your code decides which day gets which flag on every render, including recomputing the whole grid when the visible month changes. `DatePickerInput` has no controlled-value helpers beyond what a native `<input>` already gives you; read and write its `value` the way you would any form input.
Keyboard and accessibility
`CalendarGrid`'s `role="grid"` structure is correct, but grid-style arrow-key navigation between days isn't wired up — you'd need to manage focus movement and `tabindex` yourself to match the roving-tabindex pattern the ARIA grid role expects. `CalendarPreviousButton` and `CalendarNextButton` default to `aria-label="Previous month"`/`"Next month"` (overridable via `children`), so navigation controls are at least labeled for screen readers out of the box. `DatePickerInput` inherits full native `<input>` keyboard support for free since it's a real `<input type="date">` by default.
Styling and tokens
Every calendar part carries a `data-slot` (`calendar-day`, `calendar-nav`, `calendar-grid`, and so on), and `CalendarDay` additionally exposes `data-selected`, `data-today`, `data-outside`, `data-range-start`, `data-range-middle`, and `data-range-end` so you can style day states from CSS without reaching into JavaScript. The nav buttons pick up the shared `btn btn-icon btn-ghost` classes, matching icon buttons elsewhere in the catalog. `DatePickerInput` applies the same `input` class as `Input` and other form fields.
API
Everything except `CalendarDay` accepts only the generic `CatalogComponentProps` shape (`as`, `asChild`, `class`, `children`, `ref`) with no component-specific typed props. `CalendarDay` adds the seven typed booleans listed above. `DatePickerInput` accepts a `type` prop, defaulting to `"date"`, plus whatever native `<input>` attributes you spread in — there's no `DatePickerProps` type covering things like `min`, `max`, or a selected-range shape, because that logic doesn't exist here.
Edge cases
Multi-date and range selection are entirely your responsibility — the `rangeStart`/`rangeMiddle`/`rangeEnd` flags exist so you have somewhere to put the result, not because the component computes ranges for you. If you need a popover-attached date picker rather than a bare input, you'll have to pair `DatePicker` with Popover yourself; there's no built-in trigger/content relationship between the two.
Related pages
See Popover if you're building a calendar-in-a-popover date picker, since Date Picker doesn't include that wiring. See Native Select and Input OTP for a comparison of experimental components where the native element does more of the accessibility work for you.