Browse docs
Browse docs
Calendar is a standalone, inline month grid for picking a single date. It is
a primitive — always visible, no popup, no form-bridge or RBAC integration.
For a form-bound date field use DatePicker,
which pairs a trigger with a Calendar popover.
Dates are plain ISO YYYY-MM-DD strings throughout — no time, no time zone. The
month grid, keyboard navigation, and localization come from the headless
@dashforge/calendar-core engine; this
Calendar is the Tailwind presentation layer over it — the same engine the
MUI @dashforge/ui calendar renders.
import { Calendar } from '@dashforge/tw';
<Calendar
defaultValue="2026-05-20"
onChange={(iso) => console.log(iso)}
/>A basic uncontrolled calendar — defaultValue seeds the selection, the grid
manages it from there.
import { Calendar } from '@dashforge/tw';
<Calendar defaultValue="2026-05-20" />minDate / maxDate bound the selectable range; disabledDates blocks
specific days. isDateDisabled (a predicate) covers rule-based cases such as
"weekdays only".
import { Calendar } from '@dashforge/tw';
<Calendar
defaultValue="2026-05-15"
minDate="2026-05-04"
maxDate="2026-05-29"
disabledDates={['2026-05-12', '2026-05-13', '2026-05-20']}
/>weekStartDay sets the first column (0 = Sunday, 1 = Monday). locale is
a BCP-47 tag driving the month and weekday names.
import { Calendar } from '@dashforge/tw';
<Calendar defaultValue="2026-05-20" weekStartDay={1} locale="en-GB" />Pass value + onChange to own the selection in your own state.
import { useState } from 'react';
import { Calendar, Stack, Typography } from '@dashforge/tw';
function ControlledCalendar() {
const [date, setDate] = useState<string | null>('2026-05-20');
return (
<Stack gap={2} sx="items-center">
<Calendar value={date} onChange={setDate} />
<Typography variant="caption" sx="text-neutral-500">
Selected: {date ?? '—'}
</Typography>
</Stack>
);
}Configure <Calendar> defaults application-wide.
import { patchTheme } from '@dashforge/tw-theme';
patchTheme({
components: {
Calendar: {
defaults: { weekStartDay: 1, locale: 'en-GB' },
},
},
});Configurable axes (CalendarVariantProps):
| Axis | Type | Notes |
|---|---|---|
weekStartDay | WeekDay (0 | 1 | … | 6) | First-column weekday (0 = Sunday, 1 = Monday). |
locale | string | BCP-47 locale for month + weekday names. |
Non-visual axes (value, defaultValue, onChange, month, year, minDate, maxDate, disabledDates, isDateDisabled, today, disabled, autoFocus) are per-instance — data and behavior — not theme-configurable.
Precedence chain (lowest → highest):
weekStartDay: 0, locale: 'en-US').theme.components.Calendar.defaults (application-wide).<Calendar weekStartDay={1} locale="fr-FR" />) — wins over theme.sx — appended to the root and wins over conflicting classes via tailwind-merge.TypeScript: theme.components.Calendar.defaults autocompletes to the two axes above.
Reactivity: useComponentDefaults('Calendar') subscribes to the theme store — patchTheme re-renders every mounted instance inheriting the changed axis.
| Prop | Type | Default | Description |
|---|---|---|---|
aria-label | string | — | Accessible label for the grid. Default "Calendar". |
autoFocus | boolean | — | Moves DOM focus to the active day cell on mount. |
defaultMonth | number | — | Initial displayed month (1-indexed, uncontrolled). |
defaultValue | ISODate | null | — | Initial selected date (uncontrolled). |
defaultYear | number | — | Initial displayed year (uncontrolled). |
disabled | boolean | — | Disables the whole calendar. |
disabledDates | readonly ISODate[] | — | Explicit list of disabled dates. |
isDateDisabled | (date: ISODate) => boolean | — | Predicate marking arbitrary dates disabled. |
locale | string | — | BCP-47 locale for month/weekday names. Default "en-US". |
maxDate | ISODate | — | Latest selectable date (inclusive). |
minDate | ISODate | — | Earliest selectable date (inclusive). |
month | number | — | Controlled displayed month (1-indexed). Pair with year. |
onChange | (value: ISODate) => void | — | Fired when a day is chosen. |
onMonthChange | (month: number, year: number) => void | — | Fired when the displayed month changes. |
slotProps | CalendarSlotProps | — | Per-slot className overrides. |
sx | string | — | Root-level Tailwind class override. |
testId | string | — | Test id applied to the root element. |
today | ISODate | — | Overrides "today" (ISO YYYY-MM-DD), mainly for testing. |
value | ISODate | null | — | Selected date (controlled). |
weekStartDay | WeekDay | — | Weekday of the grid's first column (0 = Sunday). Default 0. |
year | number | — | Controlled displayed year. Pair with month. |
ISODate is a YYYY-MM-DD string; WeekDay is 0 \| 1 \| … \| 6. Both come
from @dashforge/calendar-core.
<Calendar> is a compound component with 4 named slots. Each slot accepts a { className?: string } override via slotProps:
| Slot | Purpose |
|---|---|
root | Outer calendar container (bordered surface). |
header | Top row with prev/month-year/next navigation. |
grid | The 7-column day grid wrapper. |
day | Every day-cell button (applies to all 42 cells uniformly). |
<Calendar
defaultValue="2026-05-20"
sx="rounded-xl shadow-md"
slotProps={{
header: { className: 'font-semibold' },
day: { className: 'font-medium' },
}}
/>Use sx for a root-level class override; use slotProps for a specific inner region (e.g. day hover color, header typography).
role="grid" with row /
columnheader / gridcell structure.Enter / Space selects.aria-current="date"; the selected day carries
aria-pressed.Calendar has no name, no validation, no RBAC.
It does not register with DashForm. Use DatePicker for form integration.YYYY-MM-DD only. No time component and no time zone — a stored date
never drifts across zones or DST.@dashforge/calendar-core; the same engine
powers the MUI Calendar in @dashforge/ui.dashforgePreset() — no dark: variants, so dark mode follows the CSS-var
swap automatically.