Theme
Version
GitHub PyPI Discord
On this page

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>
Choose one date
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.

Submit and reset DatePicker
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.

Constrain available dates
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.

Clear and compare DatePicker states
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.

Control value and popup state
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.

Use locale-aware DatePicker output
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.

Configure logical placement
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.

Customize DatePicker
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(...).

InputTypeDefaultEffect
valueCDatePickerDate | None (CDatePickerDate)NoneSets the initial and reset canonical date or empty value.
namestr | NoneNoneSets the native transport Form field name.
formstr | NoneNoneAssociates the native transport with an external Form ID.
idstr | NonegeneratedSets the public no-JavaScript input or enhanced Button ID and owned ID prefix.
minCDatePickerDate | None (CDatePickerDate)NoneSets the inclusive minimum selectable date.
maxCDatePickerDate | None (CDatePickerDate)NoneSets the inclusive maximum selectable date.
unavailable_datesSequence[CDatePickerDate]()Marks at most 4096 unique dates focusable but unavailable.
requiredbool | NoneNoneEnables native empty-value validity outside Field; Field owns it inside Field.
disabledbool | NoneNoneBlocks opening selection clearing and Form participation outside Field; Form disabledness also wins.
readonlybool | NoneNoneKeeps the picker focusable and submitted but blocks value changes.
invalidbool | NoneNoneAdds application invalid state to revealed native validity.
clearableboolTrueShows a clear action for an optional non-empty writable value.
dismissibleboolTruePermits Escape outside and focus-outside close requests.
placementCPopoverPlacement (CPopoverPlacement)"bottom-start"Sets the preferred logical Popover placement.
match_widthboolTrueMakes the Popover at least as wide as the visible control.
first_day_of_weekLiteral[1, 2, 3, 4, 5, 6, 7] | NoneNoneOverrides the locale week start using ISO Monday 1 through Sunday 7.
show_adjacent_daysboolTrueShows selectable neighboring-month dates in the Calendar.
fixed_weeksboolTrueUses six stable Calendar rows instead of the natural month row count.
placeholderstr"Choose a date"Supplies visible empty-state text when explicitly overridden.
picker_labelstr"Choose date"Names the popup dialog and empty trigger when explicitly overridden.
change_labelstr"Change date, {date}"Formats a selected trigger name and must retain the date placeholder when explicitly overridden.
clear_labelstr"Clear date"Names the clear Button when explicitly overridden.
unavailable_messagestr"Choose an available date."Supplies native custom validity if a selected date becomes unavailable.
variantCDatePickerVariant (CDatePickerVariant)"outline"Selects outline filled or plain field treatment.
sizeCDatePickerSize (CDatePickerSize)"md"Selects coordinated control and text sizing.
class_CClassValue | None (CClassValue)NoneAdds classes to the root and merges with attrs.
styleCStyleValue | None (CStyleValue)NoneAdds styles to the root and merges with attrs.
attrsMapping[str, object] | NoneNoneAdds 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 />.

InputTypeOmitted behaviorEffect
valuecanonical string | nullReleases control at the latest committed value.Controls selected and submitted date while supplied.
openboolean | nullReleases control at the latest committed visibility.Controls popup visibility while supplied.
mincanonical string | nullUses the server minimum.Replaces or removes the inclusive minimum.
maxcanonical string | nullUses the server maximum.Replaces or removes the inclusive maximum.
unavailableDatescanonical string arrayUses the server sequence.Replaces the bounded unavailable-date set.
requiredbooleanUses server or Field state.Controls standalone required validity.
disabledbooleanUses server or owner state.Controls interaction and Form participation.
readonlybooleanUses server or owner state.Controls focusable nonmutable state.
invalidbooleanUses server or Field state.Controls application invalid state.
clearablebooleanUses the server input.Controls the optional clear action.
dismissiblebooleanUses the server input.Controls passive popup dismissal.
placementCPopoverPlacement (CPopoverPlacement)Uses the server input.Controls preferred logical placement.
matchWidthbooleanUses the server input.Controls trigger-width matching.
firstDayOfWeek1 | 2 | 3 | 4 | 5 | 6 | 7 | nullUses the server input.Replaces or restores locale week start.
showAdjacentDaysbooleanUses the server input.Controls neighboring-month cell visibility.
fixedWeeksbooleanUses the server input.Controls six-row versus natural Calendar layout.
variantCDatePickerVariant (CDatePickerVariant)Uses the server input.Controls field presentation.
sizeCDatePickerSize (CDatePickerSize)Uses the server input.Controls coordinated sizing.
onValueChangefunctionNo semantic value callback.Receives Calendar clear native and reset value requests.
onOpenChangefunctionNo 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

EventSignatureTrigger and timingDetailControlled 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.

VariableTypePurposeDefault
--cui-date-picker-backgroundcolorVisible control and clear background.Canvas or variant-derived.
--cui-date-picker-foregroundcolorText and icon color.CanvasText
--cui-date-picker-border-colorcolorVisible control and clear boundary.Mixed CanvasText.
--cui-date-picker-invalid-border-colorcolorRevealed invalid control boundary.Theme error.
--cui-date-picker-focus-colorcolorControl and clear focus outline.Highlight
--cui-date-picker-radiuslengthVisible control and clear corner radius.0.625rem
--cui-date-picker-min-block-sizelengthMinimum interactive control height.2.5rem
--cui-date-picker-padding-inlinelengthVisible control inline inset.0.75rem
--cui-date-picker-gaplengthVisible 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

AttributeElementTypeMeaning
data-emptyRootpresent | absentMarks no committed canonical value.
data-openRootpresent | absentMirrors effective popup visibility.
data-requiredRootpresent | absentMirrors effective requiredness.
data-disabledRootpresent | absentMirrors effective disabledness.
data-readonlyRootpresent | absentMirrors effective readonly state.
data-invalidRootpresent | absentMirrors application unavailable or revealed native invalidity.
data-variantRootCDatePickerVariant (CDatePickerVariant)Mirrors visual treatment.
data-sizeRootCDatePickerSize (CDatePickerSize)Mirrors coordinated sizing.
data-enhancedRootpresent | absentMarks completed custom control activation.

Selectors

Selectors for the DOM nodes in the components that you can use for CSS, inspection, and testing.

CDatePicker selectors

SelectorElementPurpose
[data-citry-ui-part="date-picker"]Root divState reflections root attrs and styling destination.
[data-citry-ui-part="fallback-input"]Native Date inputNo-JavaScript control and enhanced Form reset validity transport.
[data-citry-ui-part="enhanced-control"]Layout divGroups the Popover activator and optional clear action.
[data-citry-ui-part="control"]Native ButtonFull-width popup activator and enhanced public focus target.
[data-citry-ui-part="value"]SpanDisplays localized selected date or placeholder.
[data-citry-ui-part="icon"]Hidden decorative SVGIdentifies the calendar affordance.
[data-citry-ui-part="clear"]Native ButtonRequests an empty optional value.

Interfaces

Aliases and data shapes referenced above.

Input type aliases

InterfaceDefinition
CDatePickerDatedate | str
CDatePickerVariantLiteral["outline", "filled", "plain"]
CDatePickerSizeLiteral["sm", "md", "lg"]
CDatePickerValueChangeSourceLiteral["calendar", "clear", "reset", "native"]
CPopoverPlacementLiteral["top-start", "top", "top-end", "bottom-start", "bottom", "bottom-end"]
CClassValuestr | Mapping[str, bool] | Sequence[CClassValue]
CStyleValuestr | Mapping[str, object] | Sequence[CStyleValue]

CDatePickerValueChangeDetail

FieldTypeDefaultMeaning
valuestring | null-Requested selected canonical date or empty state.
previousValuestring | null-Effective date before the request.
controlledboolean-Whether client value owns the commit.
sourceCDatePickerValueChangeSource (CDatePickerValueChangeSource)-Calendar clear reset or native cause.
sourceEventobject | null-Native interaction event when one exists.

CDatePickerOpenChangeDetail

FieldTypeDefaultMeaning
reasontrigger | selection | clear | reset | escape | outside | focus-outside | native | ancestor | modal-Exact request or forced-close cause.
controlledboolean-Whether client open owns ordinary visibility commits.
forcedboolean-Whether ancestor or modal safety required closure.
sourceobject | 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

KeyPurposeVariablesOverrideBrowser updates
citry-ui-date-picker-placeholderDisplays the empty control value.noneplaceholderParent i18n subscription calls tr() because the same destination later displays formatted dates.
citry-ui-date-picker-labelNames the popup and empty trigger.nonepicker_label$c-tr updates the stable title; parent subscription updates the dynamic trigger name.
citry-ui-date-picker-changeNames 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-clearNames the optional clear Button.noneclear_label$c-tr updates the stable aria-label destination.
citry-ui-date-picker-unavailableSupplies native custom validity when a selected date becomes unavailable.noneunavailable_messagei18n.bind() updates the browser-owned validity message.