DatePicker
Date picker with calendar popup. Supports single date and date range selection, validation constraints, clearable input, and multiple visual variants.
Playground
<script lang="ts">
import { DatePicker } from '@urbicon-ui/blocks';
const label = 'Date';
const placeholder = 'Select a date';
</script>
<DatePicker
{label}
{placeholder}
/>01 Examples
Basic DatePicker
<script lang="ts">
import { DatePicker } from '@urbicon-ui/blocks';
let selectedDate = $state<Date | undefined>(undefined);
</script>
<div class="max-w-xs">
<DatePicker
bind:value={selectedDate}
label="Geburtsdatum"
placeholder="Datum auswaehlen"
locale="de-DE"
defaultMonth={2}
defaultYear={2026}
/>
{#if selectedDate}
<div class="bg-surface-elevated border-border-subtle mt-3 rounded-lg border p-3">
<p class="text-text-secondary text-sm">
<span class="text-text-primary font-medium">Gewaehlt:</span>
{selectedDate.toLocaleDateString('de-DE', {
weekday: 'long',
day: 'numeric',
month: 'long',
year: 'numeric'
})}
</p>
</div>
{/if}
</div>
DateRangePicker
<script lang="ts">
import { DateRangePicker } from '@urbicon-ui/blocks';
let value = $state<{ start: Date; end: Date } | undefined>(undefined);
</script>
<div class="max-w-xs">
<DateRangePicker
bind:value
label="Reisezeitraum"
placeholder="Zeitraum auswaehlen"
locale="de-DE"
defaultMonth={2}
defaultYear={2026}
/>
{#if value}
<div class="bg-surface-elevated border-border-subtle mt-3 rounded-lg border p-3">
<p class="text-text-secondary text-sm">
<span class="text-text-primary font-medium">Von:</span>
{value.start.toLocaleDateString('de-DE', {
day: 'numeric',
month: 'long',
year: 'numeric'
})}
</p>
<p class="text-text-secondary text-sm">
<span class="text-text-primary font-medium">Bis:</span>
{value.end.toLocaleDateString('de-DE', {
day: 'numeric',
month: 'long',
year: 'numeric'
})}
</p>
<p class="text-text-secondary mt-1 text-xs">
{Math.ceil((value.end.getTime() - value.start.getTime()) / (1000 * 60 * 60 * 24)) + 1} Tage
</p>
</div>
{/if}
</div>
With Constraints
<script lang="ts">
import { DatePicker } from '@urbicon-ui/blocks';
let selectedDate = $state<Date | undefined>(undefined);
const minDate = new Date(2026, 2, 1);
const maxDate = new Date(2026, 2, 31);
/** Disable weekends */
function isWeekend(date: Date): boolean {
const day = date.getDay();
return day === 0 || day === 6;
}
/** Specific holidays / blocked dates */
const holidays = [new Date(2026, 2, 6), new Date(2026, 2, 20)];
</script>
<div class="max-w-xs">
<DatePicker
bind:value={selectedDate}
label="Terminbuchung"
placeholder="Werktag waehlen"
helper="Nur Werktage im Maerz 2026, keine Feiertage."
locale="de-DE"
{minDate}
{maxDate}
isDateDisabled={isWeekend}
disabledDates={holidays}
defaultMonth={2}
defaultYear={2026}
/>
{#if selectedDate}
<div class="bg-surface-elevated border-border-subtle mt-3 rounded-lg border p-3">
<p class="text-text-secondary text-sm">
<span class="text-text-primary font-medium">Termin:</span>
{selectedDate.toLocaleDateString('de-DE', {
weekday: 'long',
day: 'numeric',
month: 'long',
year: 'numeric'
})}
</p>
</div>
{/if}
</div>
02 Accessibility
ARIA Roles
The trigger input carries aria-haspopup="dialog" and aria-expanded, so the popover's state is announced.
The embedded calendar is a role="grid" with the full ARIA
that implies.
Keyboard Navigation
Enter, Space or ArrowDown open the calendar, Escape closes it. Inside, the arrow keys move between days and weeks and PageUp/PageDown between months. Focus rings use focus-visible:, so they appear for the keyboard only.
Screen Reader Labels
The label reaches the screen reader through the input. Every day cell carries an aria-label with the full date ("Thursday, 12 March
2026"), and error and helper text are linked through aria-describedby.
Internationalisation
Formatting goes through the native Intl.DateTimeFormat with the configured locale, so weekday names, month names and the input
format follow the language without further configuration.
03 API Reference
Prop | Type | Default | Description | |
|---|---|---|---|---|
calendarVariant | defaultborderedghost | 'default' | Visual style of the calendar popup. | |
class | string | — | Additional CSS classes to apply to the DatePicker component | |
clearable | boolean | true | Allow clearing the selected date. | |
closeOnClickOutside | boolean | true | Whether the popover closes on outside click. | |
closeOnEscape | boolean | true | Whether the popover closes on Escape key. | |
closeOnSelect | boolean | true | Close popover after selecting a date. | |
defaultMonth | MonthIndex | — | Default month shown when the picker opens without a value. 0–11. | |
defaultYear | number | — | Default year shown when the picker opens without a value. | |
disabled | boolean | false | Disable the entire picker. | |
disabledDates | Date[] | — | Specific dates that are disabled. | |
displayFormat | DateFormatOptions | — | Intl.DateTimeFormat options for the displayed date. | |
error | string | — | Error message shown below the input. | |
fixedWeeks | boolean | true | Always show 6 week rows, so the overlay keeps its height while paging
months. Set false to let it shrink to 4 or 5 rows. | |
helper | string | — | Helper text shown below the input. | |
inputVariant | outlinedfilledghostunderline | 'outlined' | InputVariant property for the DatePicker component | |
isDateDisabled | (date: Date) => boolean | — | Predicate that disables specific dates. Errors thrown by the predicate are caught and logged; the date is then treated as allowed so a faulty consumer callback can't take the picker down. | |
label | string | — | Label above the input. | |
locale | string | 'auto' | BCP 47 locale tag for date formatting — month names, weekday names and the
header title. Defaults to 'auto', which follows the active
<I18nProvider> locale, so an app that already declares its language does
not have to repeat it here. SSR-safe: the locale comes from context, so the
server and the client resolve the same tag (Intl with undefined would
follow the runtime and disagree across hydration). Falls back to the base
locale (en) when no provider is mounted. Pass an explicit tag
(e.g. 'de-DE', 'ja-JP') to override.
Until 2026-07-31 this defaulted to the literal 'de-DE', so an
English app rendered German month names unless every date component was
passed locale by hand. | |
maxDate | Date | — | Latest selectable date. | |
minDate | Date | — | Earliest selectable date. | |
mint | MintProp | 'none' | Micro-interaction preset forwarded to the inner Input. | |
name | string | — | Shared name for native form submission. When set, a hidden input
is rendered carrying the serialized date — matching what the user
picked, so the visible input's locale-formatted display string is
never submitted instead.
Empty / unset values submit as "" so the field still appears in
the FormData payload. | |
onClickOutside | () => void | — | Fires after an outside click closes the popover. Notification only —
does NOT govern whether close happens. That is controlled by
closeOnClickOutside. | |
onEscape | () => void | — | Fires after Escape closes the popover. Notification only — does NOT
govern whether close happens. That is controlled by closeOnEscape. | |
onOpenChange | (open: boolean) => void | — | Fires when the popover opens or closes. | |
onValueChange | (value: Date | undefined) => void | — | Fires when the selected date changes. | |
placeholder | string | — | Placeholder when no date is selected. | |
required | boolean | false | Mark input as required. | |
showOutsideDays | boolean | true | Show days from adjacent months. | |
showWeekNumbers | boolean | false | Show ISO week numbers. | |
size | xssmmdlg +1 more | 'md' | Size variant that controls dimensions and spacing of the DatePicker | |
value | Date | string | null | — | Currently selected date. Supports bind:value.
Accepts a Date, an ISO timestamp string, or null / undefined.
Internally coerced to a Date; the picker emits Date instances
via DatePickerProps.onValueChange. When both bind:value and
onValueChange are wired, both fire on every user-driven change —
pick one to drive side-effects (saves, analytics) to avoid duplicates. | |
valueFormat | dateiso | 'date' | Format used to serialise the date for the hidden form input.
- 'date' (default): YYYY-MM-DD in the local timezone — matches
the native <input type="date"> payload and Zod schemas like
z.string().regex(/^\d{4}-\d{2}-\d{2}$/).transform((v) => new Date(v)).
- 'iso': full ISO-8601 with Z suffix (UTC). Use this when the
downstream schema expects a parseable timestamp string (e.g. a
Drizzle timestamp({ withTimezone: true, mode: 'date' }) column).
Only relevant when DatePickerProps.name is set. | |
weekStartsOn | WeekdayIndex | 1 | First day of the week. 0 = Sunday, 1 = Monday. | |
...HTMLAttributes<HTMLDivElement> inherited | HTMLAttributes | — | HTML attributes (excluding: 'children') |
04 Types
Local type definitions used by this component.
Name | Kind | Category | Used by | Description | |
|---|---|---|---|---|---|
DatePickerProps | interface | props | 0 | — | |
DateRangePickerProps | interface | props | 0 | — | |
DatePickerPreset | interface | helper | 0 | — | |
DateRangePreset | interface | helper | 0 | — | |
MintProp | type | helper | 1 | — | |
MonthIndex | type | helper | 1 | Month index used by Date#getMonth(). | |
WeekdayIndex | type | helper | 1 | Weekday index used by Date#getDay(). | |
DateRange | interface | helper | 0 | A date range with inclusive start and end. | |
DateFormatOptions | type | helper | 1 | — | |
MintName | type | helper | 0 | A mint name: a built-in (autocompleted), 'none' to disable, or any
consumer-registered name. (string & {}) keeps the registry open — a
custom name still type-checks, it just isn't suggested. A typo therefore
also still compiles (it resolves like an unregistered custom name and
warns at runtime); the union buys completion and docs, not validation. | |
MintConfig | interface | helper | 0 | — | |
BuiltinMintName | type | helper | 0 | Built-in mint names as a literal union, so the mint prop autocompletes
across every component — the single list the hand-curated playground knobs
and docs used to drift away from. |
05 Installation
Import
import { DatePicker, DateRangePicker } from '@urbicon-ui/blocks';
import type { DatePickerProps, DateRangePickerProps } from '@urbicon-ui/blocks';