AppDatePicker
A calendar date field with a popover — the one way to capture a date.
<app-date-picker label="Assessment date" name="assessmentDate" />A date picker captures a single calendar date through a popover calendar — an assessment date, a due date, a date of birth. <app-date-picker> is the one way to capture a date; never fall back to a raw <input type="date">, whose look and behaviour change with every browser and operating system.
It renders the shared <wui-datepicker> control and takes its look entirely from @webority/theme, so the Razor <app-date-picker> and the React <AppDatePicker> render an identical calendar on every Webority surface.
Playground
Every attribute, live. Each change re-renders the real tag helper on the server, so the markup underneath is the exact call that produced the field above it.
Value and onChange
The field is form-associated — value seeds the initial ISO date string (YYYY-MM-DD) and it posts the chosen date under name. The element also dispatches a native change event you can listen for. Store and compare the ISO string, never a localized label.
Show code
<app-date-picker label="Assessment date" name="assessmentDate" />
<input type="date"> renders a different widget in every browser and OS, and can't match the portal's chrome. <app-date-picker> gives one calendar everywhere, styled from the shared theme.Min and max
Constrain the selectable window with min and max — the calendar disables everything outside it, so an invalid date is impossible to pick.
July 2026 only — days outside the window can't be picked.
Show code
<app-date-picker label="Reporting date" name="reportingDate" value="2026-07-15" min="2026-07-01" max="2026-07-31" />
Placeholder
placeholder sets the empty-state hint inside the field. It supplements a label — it never replaces one.
Show code
<app-date-picker label="Due date" name="dueDate" placeholder="Pick a due date" />
Week start
first-day sets which weekday the calendar starts on — 0 Sunday (default) through 6 Saturday. Match it to the locale your users expect.
Open it — the week runs Monday → Sunday.
Show code
<app-date-picker label="Delivery date" name="deliveryDate" first-day="1" />
PageUp/PageDown move by month (hold Shift for a year), Home/End jump to the week edges, Enter selects, and Esc closes. A Today shortcut sits in the footer.Width
The field defaults to a fixed, compact width — a date is a single short value, and the calendar icon sits at the right edge. Resize it with a date-w-* class (date-w-sm, date-w-md, date-w-lg, date-w-full), or set the --wui-datepicker-width variable to any value.
Show code
<app-date-picker label="Small" class="date-w-sm" /> <app-date-picker label="Large" class="date-w-lg" /> <app-date-picker label="Full" class="date-w-full" />
Sizes
size sets the control height — sm, md (default), lg — reusing AppInput's tiers so a date field lines up with the inputs beside it.
Show code
<app-date-picker label="Small" size="sm" /> <app-date-picker label="Medium" /> <app-date-picker label="Large" size="lg" />
States
disabled locks the field; error swaps the hint for a rejection message and marks the trigger aria-invalid; required adds the marker to the label and the constraint to the control.
Show code
<app-date-picker label="Locked" value="2026-07-10" disabled="true" /> <app-date-picker label="Assessment date" required="true" /> <app-date-picker label="Assessment date" error="Pick a date" />
When to use
Use it when
- Capturing a single calendar date — assessment date, due date, date of birth.
- You need one consistent calendar across every browser and both surfaces.
- Restricting selection to a valid window with min / max.
Reach for something else when
- You need a date and a time of day. → a date-time control
- You are capturing a start-and-end range. → two AppDatePickers
- The value is free text, not a date. → AppInput
- You are picking from a fixed list of labels. → AppSelect
Best practices
Every option
The whole surface of the component, one cell per value — bounds, week start, sizes, and every field state.
min / max — bounds
min="2026-07-01" (no max)max="2026-07-31" (no min)min + max — both boundsfirst-day — every weekday
first-day="0"
first-day="1"
first-day="2"
first-day="3"
first-day="4"
first-day="5"
first-day="6"
size
size="sm"
size="md"
size="lg"
state
(empty)populateddisabledrequired (label marker)errorerror + requiredhint (no error)disabled + populatedplaceholder
(default) "Enter Date"placeholder="Pick a due date"<app-date-picker> (and the shared <wui-datepicker>) has no readonly attribute — the nearest equivalent is disabled, shown above. There is also no clearable toggle: every populated calendar always shows a Clear link in its footer, so clearing is built in rather than opt-in.Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
| label | string | — | Field label above the control. |
| name | string | — | Form field name the ISO date posts under; also the element id. |
| value | string | — | Initial selected date as an ISO string (YYYY-MM-DD). |
| min | string | — | Earliest selectable date (ISO). Days before it are disabled. |
| max | string | — | Latest selectable date (ISO). Days after it are disabled. |
| placeholder | string | Enter Date | Empty-state text inside the field. |
| required | bool | false | Adds the required marker to the label. |
| hint | string | — | Helper text below the field (shown when there is no error). |
| error | string | — | Field-level error message shown below the control. |
| disabled | bool | — | Disable the control. |
| size | string | md | Control height tier — sm | md | lg, matching AppInput. |
| first-day | int | 0 | First weekday of the calendar — 0 Sunday (default), 1 Monday, … 6 Saturday. |
| aria-label | string | — | Accessible name for the control, when it should differ from the visible label. Falls back to the label. |
| id | string | — | Explicit id for the control, which the label's for then points at. Omit it to keep the name-derived id. |
| input-class | string | — | Extra classes on the control itself (the wui-datepicker) — the React className counterpart. The plain class attribute merges onto the .field wrapper instead. |