DatePicker
Use CDatePicker when an application needs Citry's consistent localized Calendar in a compact field-like control. Its display follows the active locale, while its value and Form output remain canonical YYYY-MM-DD dates.
Choose one date
Compose DatePicker in CField for a visible label, description, error, and shared required, disabled, readonly, or invalid state.
<c-CField required>
<c-fill name="label">Arrival date</c-fill>
<c-fill name="default"><c-CDatePicker name="arrival" /></c-fill>
</c-CField>
Show code
# ruff: noqa: E501 - embedded example markup and CSS stay readable as authored
from datetime import date
from typing import Any
import citry_ui
from citry import Component, citry
from citry_ui import CDatePicker
citry.register_library(citry_ui)
class BasicDatePicker(Component):
class Kwargs:
pass
class Slots:
pass
def template_data(self, kwargs: Kwargs, slots: Slots) -> dict[str, Any]: # noqa: ARG002
return {"python_picker": CDatePicker(value=date(2026, 8, 19))}
template = """
<section class="date-picker-demo-grid">
<c-CField required>
<c-fill name="label">Arrival date</c-fill>
<c-fill name="description">Choose your check-in day.</c-fill>
<c-fill name="default"><c-CDatePicker name="arrival" value="2026-08-19" /></c-fill>
</c-CField>
<article><h3>Python composition</h3>{{ python_picker }}</article>
</section>
"""
css = ":where(.date-picker-demo-grid){display:grid;grid-template-columns:repeat(auto-fit,minmax(16rem,1fr));gap:1.25rem}:where(.date-picker-demo-grid article){display:grid;align-content:start;gap:.75rem}:where(.date-picker-demo-grid h3){margin:0}"
preview = BasicDatePicker()
preview # noqa: B018
The whole visible field is a native Button, not a small detached icon. Opening moves focus to the selected date or the Calendar's current focus candidate. Selecting an available date closes the Popover and restores focus to the field.
Pick the right date family
Use CDateInput when direct native editing, the browser's platform picker, or the shortest no-JavaScript path is the priority. Use CCalendar when dates must stay visible. DatePicker is the composed popup route and deliberately does not parse localized typed text.
Submit and reset a canonical value
One native Date input owns name, form, required validity, reset, and FormData. Enhancement hides it visually and gives its public ID to the visible Button. Without JavaScript it remains the complete usable control.
Show code
# ruff: noqa: E501 - embedded example markup and CSS stay readable as authored
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class DatePickerForm(Component):
template = """
<section x-data="{submitted:'Submit to inspect FormData'}">
<form @submit.prevent="submitted=JSON.stringify(Array.from(new FormData($event.target).entries()))">
<c-CField control_id="trip-date" required>
<c-fill name="label">Trip date</c-fill>
<c-fill name="description">The submitted value stays canonical.</c-fill>
<c-fill name="default"><c-CDatePicker id="trip-date" name="trip_date" value="2026-08-19" /></c-fill>
<c-fill name="error">Choose a trip date.</c-fill>
</c-CField>
<div><button type="submit">Submit</button> <button type="reset">Reset</button></div>
</form>
<output x-text="submitted">Submit to inspect FormData</output>
</section>
"""
css = ":where(form){display:grid;gap:.75rem;max-inline-size:28rem}:where(output){display:block;margin-block-start:.75rem;overflow-wrap:anywhere}"
preview = DatePickerForm()
preview # noqa: B018
Uncontrolled user selection emits bubbling native input followed by change. Controlled requests wait for the owner and emit neither transport event until the owner commits its prop.
Bound and block dates
min and max are inclusive. unavailable_dates accepts at most 4096 unique exact dates. Calendar keeps unavailable dates focusable for inspection but rejects selection. Always validate availability again on the server.
Show code
# ruff: noqa: E501 - embedded example markup stays readable as authored
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class DatePickerConstraints(Component):
template = """
<c-CField>
<c-fill name="label">Workshop day</c-fill>
<c-fill name="description">August 20, 24, and 27 are already booked.</c-fill>
<c-fill name="default">
<c-CDatePicker value="2026-08-19" min="2026-08-10" max="2026-09-15" c-unavailable_dates="('2026-08-20','2026-08-24','2026-08-27')" />
</c-fill>
</c-CField>
"""
preview = DatePickerConstraints()
preview # noqa: B018
Clear and compare states
An optional non-empty DatePicker shows a clear Button by default. Required controls never expose it. Readonly permits opening and Calendar navigation but blocks selection; disabled blocks opening and Form participation.
Show code
# ruff: noqa: E501 - embedded example markup and CSS stay readable as authored
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class DatePickerStates(Component):
template = """
<section class="date-picker-states">
<article><h3>Optional and clearable</h3><c-CDatePicker value="2026-08-19" /></article>
<article><h3>Required</h3><c-CDatePicker value="2026-08-20" required /></article>
<article><h3>Readonly</h3><c-CDatePicker value="2026-08-21" readonly /></article>
<article><h3>Disabled</h3><c-CDatePicker value="2026-08-22" disabled /></article>
<article><h3>Invalid large</h3><c-CDatePicker value="2026-08-23" invalid size="lg" /></article>
<article><h3>Small filled</h3><c-CDatePicker value="2026-08-24" variant="filled" size="sm" /></article>
</section>
"""
css = ":where(.date-picker-states){display:grid;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));gap:1rem}:where(.date-picker-states article){display:grid;align-content:start;gap:.5rem}:where(.date-picker-states h3){margin:0;font-size:.9rem}"
preview = DatePickerStates()
preview # noqa: B018
Control value and open state independently
Client value and open are separate controlled channels. A controlled selection or open/close interaction calls onValueChange or onOpenChange without claiming it committed. Return the accepted value through $c-props.
Show code
# ruff: noqa: E501 - embedded example markup stays readable as authored
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class ControlledDatePicker(Component):
template = """
<section x-data="{value:'2026-08-19',open:false,last:'No request yet'}">
<p>Value: <strong x-text="value || 'empty'"></strong>; popup: <strong x-text="open ? 'open' : 'closed'"></strong></p>
<c-CDatePicker
value="2026-08-19"
$c-props="{value,open,onValueChange:(next,detail)=>{last=`${detail.source}: ${next}`;value=next},onOpenChange:(next,detail)=>{last=`${detail.reason}: ${next}`;open=next}}"
/>
<div><button type="button" @click="value='2026-08-25'">Set August 25</button> <button type="button" @click="open=!open">Toggle popup</button></div>
<output x-text="last">No request yet</output>
</section>
"""
css = ":where(section){display:grid;gap:.75rem;max-inline-size:28rem}:where(section p){margin:0}"
preview = ControlledDatePicker()
preview # noqa: B018
Omitting either client prop releases that channel at its latest committed state. The other channel remains controlled.
Follow the active locale
Under a client-enabled <c-i18n> provider, the display value, trigger name, popup title, clear name, Calendar heading, weekdays, day numbers, and full date names switch in place. The ISO value does not change. Non-Gregorian display calendars remain mapped to the same Gregorian domain date.
Show code
# ruff: noqa: E501 - embedded example markup and CSS stay readable as authored
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class DatePickerLocales(Component):
template = """
<section class="date-picker-locales">
<article><h3>Provider locale week</h3><c-CDatePicker value="2026-08-19" /></article>
<article><h3>Explicit Monday start</h3><c-CDatePicker value="2026-08-19" c-first_day_of_week="1" /></article>
<article lang="ar" dir="rtl"><h3>RTL scope</h3><c-CDatePicker value="2026-08-19" /></article>
</section>
"""
css = ":where(.date-picker-locales){display:grid;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));gap:1rem}:where(.date-picker-locales article){display:grid;align-content:start;gap:.5rem;padding:.75rem}:where(.date-picker-locales h3){margin:0}"
preview = DatePickerLocales()
preview # noqa: B018
first_day_of_week overrides only the week start. Leave it unset to follow locale data.
Configure placement
DatePicker uses the existing non-modal Popover contract. Choose one of six logical placements and use match_width when the surface should be at least the field width. Collision repair may use another rendered side.
Show code
# ruff: noqa: E501 - embedded example markup and CSS stay readable as authored
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class DatePickerPlacement(Component):
template = """
<section class="date-picker-placement">
<article><h3>Bottom start and matched</h3><c-CDatePicker value="2026-08-19" /></article>
<article><h3>Top end and intrinsic</h3><c-CDatePicker value="2026-08-20" placement="top-end" c-match_width="False" /></article>
</section>
"""
css = ":where(.date-picker-placement){display:grid;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));gap:3rem;min-block-size:28rem;align-items:center}:where(.date-picker-placement article){display:grid;gap:.5rem}:where(.date-picker-placement h3){margin:0}"
preview = DatePickerPlacement()
preview # noqa: B018
Escape and passive outside or focus-outside interaction close a dismissible picker. It does not trap focus, lock the page, or make background content inert.
Customize documented anatomy
Variants, sizes, public --cui-date-picker-* variables, and stable data-citry-ui-part selectors style the field. The nested Calendar and Popover keep their own public variables.
Show code
# ruff: noqa: E501 - embedded example markup and CSS stay readable as authored
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class StyledDatePicker(Component):
template = """
<c-CDatePicker class_="brand-date-picker" value="2026-08-19" c-unavailable_dates="('2026-08-20',)" />
"""
css = """
:where(.brand-date-picker){--cui-date-picker-background:#f0fdfa;--cui-date-picker-foreground:#134e4a;--cui-date-picker-border-color:#0f766e;--cui-date-picker-focus-color:#0d9488;--cui-date-picker-radius:1rem;--cui-calendar-selected-background:#0f766e;--cui-calendar-selected-foreground:white;max-inline-size:24rem}
@media (prefers-color-scheme:dark){:where(.brand-date-picker){--cui-date-picker-background:#132f2d;--cui-date-picker-foreground:#ccfbf1;--cui-date-picker-border-color:#5eead4}}
"""
preview = StyledDatePicker()
preview # noqa: B018
The Calendar grid follows its complete roving-focus keyboard contract. Manual screen-reader review remains important for popup grids, especially on mobile.
API reference
Inputs
CDatePicker server inputs
Server inputs are passed in a template through <c-CDatePicker ... /> or in Python through CDatePicker(...).
| Input | Type | Default | Effect |
|---|---|---|---|
value | CDatePickerDate | None (CDatePickerDate) | None | Sets the initial and reset canonical date or empty value. |
name | str | None | None | Sets the native transport Form field name. |
form | str | None | None | Associates the native transport with an external Form ID. |
id | str | None | generated | Sets the public no-JavaScript input or enhanced Button ID and owned ID prefix. |
min | CDatePickerDate | None (CDatePickerDate) | None | Sets the inclusive minimum selectable date. |
max | CDatePickerDate | None (CDatePickerDate) | None | Sets the inclusive maximum selectable date. |
unavailable_dates | Sequence[CDatePickerDate] | () | Marks at most 4096 unique dates focusable but unavailable. |
required | bool | None | None | Enables native empty-value validity outside Field; Field owns it inside Field. |
disabled | bool | None | None | Blocks opening selection clearing and Form participation outside Field; Form disabledness also wins. |
readonly | bool | None | None | Keeps the picker focusable and submitted but blocks value changes. |
invalid | bool | None | None | Adds application invalid state to revealed native validity. |
clearable | bool | True | Shows a clear action for an optional non-empty writable value. |
dismissible | bool | True | Permits Escape outside and focus-outside close requests. |
placement | CPopoverPlacement (CPopoverPlacement) | "bottom-start" | Sets the preferred logical Popover placement. |
match_width | bool | True | Makes the Popover at least as wide as the visible control. |
first_day_of_week | Literal[1, 2, 3, 4, 5, 6, 7] | None | None | Overrides the locale week start using ISO Monday 1 through Sunday 7. |
show_adjacent_days | bool | True | Shows selectable neighboring-month dates in the Calendar. |
fixed_weeks | bool | True | Uses six stable Calendar rows instead of the natural month row count. |
placeholder | str | "Choose a date" | Supplies visible empty-state text when explicitly overridden. |
picker_label | str | "Choose date" | Names the popup dialog and empty trigger when explicitly overridden. |
change_label | str | "Change date, {date}" | Formats a selected trigger name and must retain the date placeholder when explicitly overridden. |
clear_label | str | "Clear date" | Names the clear Button when explicitly overridden. |
unavailable_message | str | "Choose an available date." | Supplies native custom validity if a selected date becomes unavailable. |
variant | CDatePickerVariant (CDatePickerVariant) | "outline" | Selects outline filled or plain field treatment. |
size | CDatePickerSize (CDatePickerSize) | "md" | Selects coordinated control and text sizing. |
class_ | CClassValue | None (CClassValue) | None | Adds classes to the root and merges with attrs. |
style | CStyleValue | None (CStyleValue) | None | Adds styles to the root and merges with attrs. |
attrs | Mapping[str, object] | None | None | Adds copied allowed root attributes without replacing owned state identity or runtime markers. |
CDatePicker client inputs
Client inputs are passed in the browser through the $c-props="{ ... }" attribute on <c-CDatePicker />.
| Input | Type | Omitted behavior | Effect |
|---|---|---|---|
value | canonical string | null | Releases control at the latest committed value. | Controls selected and submitted date while supplied. |
open | boolean | null | Releases control at the latest committed visibility. | Controls popup visibility while supplied. |
min | canonical string | null | Uses the server minimum. | Replaces or removes the inclusive minimum. |
max | canonical string | null | Uses the server maximum. | Replaces or removes the inclusive maximum. |
unavailableDates | canonical string array | Uses the server sequence. | Replaces the bounded unavailable-date set. |
required | boolean | Uses server or Field state. | Controls standalone required validity. |
disabled | boolean | Uses server or owner state. | Controls interaction and Form participation. |
readonly | boolean | Uses server or owner state. | Controls focusable nonmutable state. |
invalid | boolean | Uses server or Field state. | Controls application invalid state. |
clearable | boolean | Uses the server input. | Controls the optional clear action. |
dismissible | boolean | Uses the server input. | Controls passive popup dismissal. |
placement | CPopoverPlacement (CPopoverPlacement) | Uses the server input. | Controls preferred logical placement. |
matchWidth | boolean | Uses the server input. | Controls trigger-width matching. |
firstDayOfWeek | 1 | 2 | 3 | 4 | 5 | 6 | 7 | null | Uses the server input. | Replaces or restores locale week start. |
showAdjacentDays | boolean | Uses the server input. | Controls neighboring-month cell visibility. |
fixedWeeks | boolean | Uses the server input. | Controls six-row versus natural Calendar layout. |
variant | CDatePickerVariant (CDatePickerVariant) | Uses the server input. | Controls field presentation. |
size | CDatePickerSize (CDatePickerSize) | Uses the server input. | Controls coordinated sizing. |
onValueChange | function | No semantic value callback. | Receives Calendar clear native and reset value requests. |
onOpenChange | function | No semantic visibility callback. | Receives trigger selection dismissal reset and forced-close requests. |
Slots
-
Events
Component events are callback inputs supplied through $c-props. Native browser events remain available through Alpine @... attributes.
CDatePicker events
| Event | Signature | Trigger and timing | Detail | Controlled and cancellation behavior |
|---|---|---|---|---|
onValueChange | (value: string | null, detail: CDatePickerValueChangeDetail) => void (CDatePickerValueChangeDetail) | Calendar selection clear reset or native fallback editing requests another value. | {value, previousValue, controlled, source, sourceEvent} (CDatePickerValueChangeDetail) | Uncontrolled user commits emit native input/change; controlled requests wait for the owner. |
onOpenChange | (open: boolean, detail: CDatePickerOpenChangeDetail) => void (CDatePickerOpenChangeDetail) | Trigger selection clear reset Escape outside focus-outside native or forced layer changes request visibility. | {reason, controlled, forced, source} (CDatePickerOpenChangeDetail) | Uncontrolled requests commit before notification; controlled requests wait except forced safety closure. |
Methods
-
CSS
CSS variables to theme the components. Set them on an ancestor or the component itself.
CDatePicker CSS variables
Apply these variables to CDatePicker or one of its ancestors.
| Variable | Type | Purpose | Default |
|---|---|---|---|
--cui-date-picker-background | color | Visible control and clear background. | Canvas or variant-derived. |
--cui-date-picker-foreground | color | Text and icon color. | CanvasText |
--cui-date-picker-border-color | color | Visible control and clear boundary. | Mixed CanvasText. |
--cui-date-picker-invalid-border-color | color | Revealed invalid control boundary. | Theme error. |
--cui-date-picker-focus-color | color | Control and clear focus outline. | Highlight |
--cui-date-picker-radius | length | Visible control and clear corner radius. | 0.625rem |
--cui-date-picker-min-block-size | length | Minimum interactive control height. | 2.5rem |
--cui-date-picker-padding-inline | length | Visible control inline inset. | 0.75rem |
--cui-date-picker-gap | length | Visible value and icon gap. | 0.5rem |
Attributes
HTML attributes defined on the components that you can refer to for CSS, inspection, and testing. Read-only.
CDatePicker attributes
| Attribute | Element | Type | Meaning |
|---|---|---|---|
data-empty | Root | present | absent | Marks no committed canonical value. |
data-open | Root | present | absent | Mirrors effective popup visibility. |
data-required | Root | present | absent | Mirrors effective requiredness. |
data-disabled | Root | present | absent | Mirrors effective disabledness. |
data-readonly | Root | present | absent | Mirrors effective readonly state. |
data-invalid | Root | present | absent | Mirrors application unavailable or revealed native invalidity. |
data-variant | Root | CDatePickerVariant (CDatePickerVariant) | Mirrors visual treatment. |
data-size | Root | CDatePickerSize (CDatePickerSize) | Mirrors coordinated sizing. |
data-enhanced | Root | present | absent | Marks completed custom control activation. |
Selectors
Selectors for the DOM nodes in the components that you can use for CSS, inspection, and testing.
CDatePicker selectors
| Selector | Element | Purpose |
|---|---|---|
[data-citry-ui-part="date-picker"] | Root div | State reflections root attrs and styling destination. |
[data-citry-ui-part="fallback-input"] | Native Date input | No-JavaScript control and enhanced Form reset validity transport. |
[data-citry-ui-part="enhanced-control"] | Layout div | Groups the Popover activator and optional clear action. |
[data-citry-ui-part="control"] | Native Button | Full-width popup activator and enhanced public focus target. |
[data-citry-ui-part="value"] | Span | Displays localized selected date or placeholder. |
[data-citry-ui-part="icon"] | Hidden decorative SVG | Identifies the calendar affordance. |
[data-citry-ui-part="clear"] | Native Button | Requests an empty optional value. |
Interfaces
Aliases and data shapes referenced above.
Input type aliases
| Interface | Definition |
|---|---|
CDatePickerDate | date | str |
CDatePickerVariant | Literal["outline", "filled", "plain"] |
CDatePickerSize | Literal["sm", "md", "lg"] |
CDatePickerValueChangeSource | Literal["calendar", "clear", "reset", "native"] |
CPopoverPlacement | Literal["top-start", "top", "top-end", "bottom-start", "bottom", "bottom-end"] |
CClassValue | str | Mapping[str, bool] | Sequence[CClassValue] |
CStyleValue | str | Mapping[str, object] | Sequence[CStyleValue] |
CDatePickerValueChangeDetail
| Field | Type | Default | Meaning |
|---|---|---|---|
value | string | null | - | Requested selected canonical date or empty state. |
previousValue | string | null | - | Effective date before the request. |
controlled | boolean | - | Whether client value owns the commit. |
source | CDatePickerValueChangeSource (CDatePickerValueChangeSource) | - | Calendar clear reset or native cause. |
sourceEvent | object | null | - | Native interaction event when one exists. |
CDatePickerOpenChangeDetail
| Field | Type | Default | Meaning |
|---|---|---|---|
reason | trigger | selection | clear | reset | escape | outside | focus-outside | native | ancestor | modal | - | Exact request or forced-close cause. |
controlled | boolean | - | Whether client open owns ordinary visibility commits. |
forced | boolean | - | Whether ancestor or modal safety required closure. |
source | object | null | - | Associated browser source when one exists. |
Translation keys
Catalog keys used by this family. An explicit component input or slot listed in Override takes precedence over the catalog for that instance.
CDatePicker translation keys
| Key | Purpose | Variables | Override | Browser updates |
|---|---|---|---|---|
citry-ui-date-picker-placeholder | Displays the empty control value. | none | placeholder | Parent i18n subscription calls tr() because the same destination later displays formatted dates. |
citry-ui-date-picker-label | Names the popup and empty trigger. | none | picker_label | $c-tr updates the stable title; parent subscription updates the dynamic trigger name. |
citry-ui-date-picker-change | Names a selected trigger. | `date: str` localized by `citry-ui-date-picker-display` | change_label containing {date} | Parent i18n subscription recomputes the formatted value and calls tr(). |
citry-ui-date-picker-clear | Names the optional clear Button. | none | clear_label | $c-tr updates the stable aria-label destination. |
citry-ui-date-picker-unavailable | Supplies native custom validity when a selected date becomes unavailable. | none | unavailable_message | i18n.bind() updates the browser-owned validity message. |