Browse docs
Browse docs
DatePicker is a form-connected single-date field: a read-only trigger button
paired with a Calendar popover. It integrates
with DashForm and RBAC automatically — registration, validation, error
gating, reactive visibility, and access control are handled internally. The
name prop connects the field to the form schema.
The stored value is a plain ISO calendar date — YYYY-MM-DD — or null.
Unlike the native DateTimePicker, a pure date carries no time and no time
zone, which removes the whole class of DST round-trip hazards.
import { DashForm } from '@dashforge/forms';
import { DatePicker } from '@dashforge/tw';
<DashForm onSubmit={(data) => console.log(data)}>
<DatePicker
name="startDate"
label="Start date"
rules={{ required: 'Please pick a date' }}
/>
</DashForm>A basic field — click the trigger to open the calendar popover.
import { DatePicker } from '@dashforge/tw';
<DatePicker name="startDate" label="Start date" />minDate / maxDate bound the selectable range; disabledDates and the
isDateDisabled predicate block specific days.
May 2026 only
import { DatePicker } from '@dashforge/tw';
<DatePicker
name="bookingDate"
label="Booking date"
defaultValue="2026-05-15"
minDate="2026-05-01"
maxDate="2026-05-31"
helperText="May 2026 only"
/>Pass required and rules — the field reports errors through the form bridge,
gated on touch / submit.
Required field
import { DatePicker } from '@dashforge/tw';
<DatePicker
name="deadline"
label="Deadline"
required
rules={{ required: 'Please pick a deadline' }}
helperText="Required field"
/>locale drives both the calendar names and the trigger's display format;
weekStartDay sets the popover calendar's first column.
import { DatePicker } from '@dashforge/tw';
<DatePicker
name="dateDebut"
label="Date de début"
defaultValue="2026-05-20"
locale="fr-FR"
weekStartDay={1}
/>Configure <DatePicker> defaults application-wide.
import { patchTheme } from '@dashforge/tw-theme';
patchTheme({
components: {
DatePicker: {
defaults: { layout: 'stacked', weekStartDay: 1, locale: 'en-GB', fullWidth: false },
},
},
});Configurable axes (DatePickerVariantProps):
| Axis | Type | Notes |
|---|---|---|
layout | 'stacked' | 'inline' | Label position (above vs left of the trigger). |
weekStartDay | WeekDay (0 | 1 | … | 6) | First-column weekday of the popover calendar. |
locale | string | BCP-47 locale for the calendar names + the trigger's display format. |
fullWidth | boolean | Stretch root + trigger to container width. |
Non-visual axes (name, rules, label, helperText, placeholder, required, error, disabled, value, defaultValue, onChange, minDate, maxDate, disabledDates, isDateDisabled, access, visibleWhen) are per-instance — data / behavior / bridge integration — not theme-configurable.
Precedence chain (lowest → highest):
layout: 'stacked', weekStartDay: 0, locale: 'en-US', fullWidth: false).theme.components.DatePicker.defaults (application-wide).<DatePicker weekStartDay={1} fullWidth />) — wins over theme.sx — appended to the root and wins over conflicting classes via tailwind-merge.TypeScript: theme.components.DatePicker.defaults autocompletes to the four axes above.
Reactivity: useComponentDefaults('DatePicker') subscribes to the theme store — patchTheme re-renders every mounted instance inheriting the changed axis.
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | — | Field name — the bridge registration key. Required. |
access | AccessRequirement | — | RBAC access requirement. |
defaultValue | ISODate | null | — | Uncontrolled initial value. |
disabled | boolean | — | Disables the field. |
disabledDates | readonly ISODate[] | — | Explicit list of disabled dates. |
error | boolean | — | Explicit error state (overrides the bridge's auto error). |
fullWidth | boolean | — | Stretches the field to its container width. |
helperText | ReactNode | — | Helper text below the control (overrides a bridge error message). |
isDateDisabled | (date: ISODate) => boolean | — | Predicate marking arbitrary dates disabled. |
label | ReactNode | — | Field label. |
layout | 'stacked' | 'inline' | — | Label/control layout. |
locale | string | — | BCP-47 locale for the calendar and the display format. |
maxDate | ISODate | — | Latest selectable date (inclusive). |
minDate | ISODate | — | Earliest selectable date (inclusive). |
onChange | (value: ISODate | null) => void | — | Fired with the new ISO date (or null when cleared). |
placeholder | string | — | Placeholder shown when no date is selected. |
required | boolean | — | Marks the field required (adds the label asterisk). |
rules | unknown | — | Validation rules forwarded to the form bridge. |
slotProps | DatePickerSlotProps | — | Per-slot className overrides. |
sx | string | — | Root-level Tailwind class override. |
testId | string | — | Test id applied to the field root. |
value | ISODate | null | — | Controlled value — ISO YYYY-MM-DD or null. |
visibleWhen | (engine: Engine) => boolean | — | Reactive visibility predicate evaluated against the form engine. |
weekStartDay | WeekDay | — | Weekday of the calendar's first column (0 = Sunday). |
<DatePicker> is a compound component with 6 named slots. Each slot accepts a { className?: string } override via slotProps:
| Slot | Purpose |
|---|---|
root | Outer wrapper (label + trigger + helper/error). |
label | The <label> element. |
requiredMark | The red * when required. |
trigger | The read-only <button> that opens the popover calendar. |
helperText | Helper text line, when not in error state. |
errorText | Helper text line, when in error state. |
<DatePicker
name="startDate"
label="Start date"
sx="max-w-xs"
slotProps={{ trigger: { className: 'rounded-lg' } }}
/>Use sx for a root-level class override; use slotProps for a specific inner region (e.g. trigger border color, errorText weight). The popover calendar itself is themable via theme.components.Calendar.defaults — see Calendar.
YYYY-MM-DD storage. The bridge value is a plain calendar date or
null — no time, no offset. Read it directly; no parsing needed.DateTimePicker.DatePicker works as a standard controlled component with ISO date storage.
<DatePicker
value={startDate}
onChange={(iso) => setStartDate(iso)}
label="Start date"
/>Inside DashForm the field registers automatically — validation, error gating,
and touch tracking flow through the bridge.
<DashForm>
<DatePicker
name="deadline"
label="Deadline"
rules={{ required: 'Please pick a deadline' }}
/>
</DashForm>visibleWhen shows / hides the field from engine-driven form state.
<DatePicker
name="scheduledDate"
label="Scheduled date"
visibleWhen={(engine) => engine.getNode('schedule')?.value === true}
/>The access prop maps an RBAC decision to one of three field states — no
manual checks in the parent.
<DatePicker
name="overrideDate"
label="Override date"
access={{ resource: 'invoice', action: 'update', onUnauthorized: 'disable' }}
/>| Field | Type | Description |
|---|---|---|
resource | string | The resource being protected. |
action | string | The action being checked. |
onUnauthorized | 'hide' | 'disable' | 'readonly' | What to render when the user lacks permission. Defaults to 'hide'. |