{"name":"date-picker","title":"Date Picker","description":"A popover-style date field that combines a text input and a calendar for selecting a date.","installCommand":"bunx marko-ui add date-picker -y","usageTags":"<DatePicker>","importSnippet":"import DatePicker from \"@/components/ui/date-picker/date-picker.marko\";","usageSnippet":"<let/date=(undefined as string | undefined)/>\n\n<DatePicker value:=date/>","tags":["DatePicker"],"parts":[],"props":[{"name":"closeOnSelect","type":"boolean | undefined","required":false,"default":"true","description":"Whether the calendar should close after the date selection is complete.\nThis is ignored when the selection mode is `multiple`."},{"name":"createCalendar","type":"((identifier: CalendarIdentifier) => Calendar) | undefined","required":false,"description":"A function that creates a Calendar object for a given calendar identifier.\nEnables non-Gregorian calendar support (Persian, Buddhist, Islamic, etc.)\nwithout bundling all calendars by default."},{"name":"defaultFocusedValue","type":"string","required":false,"description":"Initial visible-month focus, as an ISO date string (`YYYY-MM-DD`).\nPins the SSR-rendered month instead of falling back to the browser's\nwall-clock \"today\" (`getTodayDate`), which would otherwise make SSR\nand hydrated markup diverge near midnight or across timezones."},{"name":"defaultOpen","type":"boolean | undefined","required":false,"description":"The initial open state of the date picker when rendered.\nUse when you don't need to control the open state of the date picker."},{"name":"defaultValue","type":"DateValue[] | undefined","required":false,"description":"The initial selected date(s) when rendered.\nUse when you don't need to control the selected date(s) of the date picker."},{"name":"defaultView","type":"DateView | undefined","required":false,"default":"day","description":"The default view of the calendar"},{"name":"dir","type":"'ltr' | 'rtl' | undefined","required":false,"default":"ltr","description":"The document's text/writing direction."},{"name":"disabled","type":"boolean | undefined","required":false,"description":"Whether the calendar is disabled."},{"name":"fixedWeeks","type":"boolean | undefined","required":false,"description":"Whether the calendar should have a fixed number of weeks.\nThis renders the calendar with 6 weeks instead of 5 or 6."},{"name":"focusedValue","type":"string","required":false,"description":"Controlled visible-month focus, as an ISO date string (`YYYY-MM-DD`)."},{"name":"format","type":"((date: DateValue, details: LocaleDetails) => string) | undefined","required":false,"description":"The format of the date to display in the input."},{"name":"getRootNode","type":"(() => ShadowRoot | Document | Node) | undefined","required":false,"description":"A root node to correctly resolve document in custom environments. E.x.: Iframes, Electron."},{"name":"ids","type":"ElementIds | undefined","required":false,"description":"The ids of the elements in the date picker. Useful for composition."},{"name":"inline","type":"boolean | undefined","required":false,"description":"Whether to render the date picker inline"},{"name":"invalid","type":"boolean | undefined","required":false,"description":"Whether the date picker is invalid"},{"name":"isDateUnavailable","type":"((date: DateValue, locale: string) => boolean) | undefined","required":false,"description":"Returns whether a date of the calendar is available."},{"name":"locale","type":"string | undefined","required":false,"default":"en-US","description":"The locale (BCP 47 language tag) to use when formatting the date."},{"name":"max","type":"DateValue | undefined","required":false,"description":"The maximum date that can be selected."},{"name":"maxSelectedDates","type":"number | undefined","required":false,"description":"The maximum number of dates that can be selected.\nThis is only applicable when `selectionMode` is `multiple`."},{"name":"maxView","type":"DateView | undefined","required":false,"default":"year","description":"The maximum view of the calendar"},{"name":"min","type":"DateValue | undefined","required":false,"description":"The minimum date that can be selected."},{"name":"minView","type":"DateView | undefined","required":false,"default":"day","description":"The minimum view of the calendar"},{"name":"name","type":"string | undefined","required":false,"description":"The `name` attribute of the input element."},{"name":"numOfMonths","type":"number | undefined","required":false,"description":"The number of months to display."},{"name":"open","type":"boolean | undefined","required":false,"description":"The controlled open state of the date picker"},{"name":"openOnClick","type":"boolean | undefined","required":false,"default":"false","description":"Whether to open the calendar when the input is clicked."},{"name":"outsideDaySelectable","type":"boolean | undefined","required":false,"default":"false","description":"Whether day outside the visible range can be selected."},{"name":"parse","type":"((value: string, details: LocaleDetails) => DateValue | undefined) | undefined","required":false,"description":"Function to parse the date from the input back to a DateValue."},{"name":"placeholder","type":"string | undefined","required":false,"description":"The placeholder text to display in the input."},{"name":"positioning","type":"PositioningOptions | undefined","required":false,"description":"The user provided options used to position the date picker content"},{"name":"readOnly","type":"boolean | undefined","required":false,"description":"Whether the calendar is read-only."},{"name":"required","type":"boolean | undefined","required":false,"description":"Whether the date picker is required"},{"name":"selectionMode","type":"SelectionMode | undefined","required":false,"default":"single","description":"The selection mode of the calendar.\n- `single` - only one date can be selected\n- `multiple` - multiple dates can be selected\n- `range` - a range of dates can be selected"},{"name":"showWeekNumbers","type":"boolean | undefined","required":false,"description":"Whether to show the week number column in the day view."},{"name":"startOfWeek","type":"number | undefined","required":false,"description":"The first day of the week.\n `0` - Sunday\n `1` - Monday\n `2` - Tuesday\n `3` - Wednesday\n `4` - Thursday\n `5` - Friday\n `6` - Saturday"},{"name":"timeZone","type":"string | undefined","required":false,"default":"UTC","description":"The time zone to use"},{"name":"translations","type":"IntlTranslations | undefined","required":false,"description":"The localized messages to use."},{"name":"value","type":"string","required":false,"description":"The selected date as an ISO date string (`YYYY-MM-DD`)."},{"name":"view","type":"DateView | undefined","required":false,"description":"The view of the calendar"}],"events":[{"name":"onFocusChange","arg":"FocusChangeDetails","description":"Function called when the focused date changes."},{"name":"onOpenChange","arg":"OpenChangeDetails","description":"Function called when the calendar opens or closes."},{"name":"onValueChange","arg":"ValueChangeDetails","description":"Function called when the value changes."},{"name":"onViewChange","arg":"ViewChangeDetails","description":"Function called when the view changes."},{"name":"onVisibleRangeChange","arg":"VisibleRangeChangeDetails","description":"Function called when the visible range changes."},{"name":"valueChange","arg":"string","description":"Function called when the value changes. Receives the new ISO date string, or `undefined` when cleared."}],"keyboard":[{"keys":"Tab / Shift+Tab","description":"Moves focus between the text input and the calendar-trigger button, then into the open calendar panel."},{"keys":"Enter / Space","description":"Opens the calendar panel when the trigger button is focused; selects the focused day when a day cell is focused."},{"keys":"Arrow keys","description":"Moves focus one day at a time within the calendar grid (composed examples get this from `Calendar`)."},{"keys":"Page Up / Page Down","description":"Moves focus to the same day in the previous/next month."},{"keys":"Home / End","description":"Moves focus to the first/last day of the visible week."},{"keys":"Escape","description":"Closes the calendar panel without changing the value."}],"accessibilityNotes":["The text input and the calendar trigger button share one `data-slot=\"date-picker-control\"` group; typing a valid date and picking one from the calendar both update the same controlled `value`.","The calendar panel is a popover (`role` and `aria-expanded` on the trigger button come from `@zag-js/date-picker`'s `getTriggerProps()`), so it's reachable and dismissible with the same keyboard model as `Popover`.","Day cells expose `aria-selected` and `aria-disabled` via `getDayTableCellTriggerProps()`; the composed `Popover`+`Calendar` examples (range, dropdown, input-sync) get the same semantics from `Calendar` directly.","Set `disabled` to remove the whole field from the tab order, or `readOnly` to keep the value visible and focusable while blocking changes from both the input and the calendar."],"examples":[{"id":"date-picker-demo","title":"Basic","source":"import DatePicker from \"@marko-ui/shadcn/ui/date-picker/date-picker.marko\";\n\nstatic const focusedValue = \"2026-08-15\";\n\n<DatePicker defaultFocusedValue=focusedValue/>","description":"A date picker with no initial value."},{"id":"date-picker-basic","title":"Simple","source":"import Field from \"@marko-ui/shadcn/ui/field/field.marko\";\nimport FieldLabel from \"@marko-ui/shadcn/ui/field/field-label.marko\";\nimport Popover from \"@marko-ui/shadcn/ui/popover/popover.marko\";\nimport Button from \"@marko-ui/shadcn/ui/button/button.marko\";\nimport Calendar from \"@marko-ui/shadcn/ui/calendar/calendar.marko\";\n\nstatic function formatDate(date?: { year: number; month: number; day: number }) {\n  if (!date) return undefined;\n  return new Date(date.year, date.month - 1, date.day).toLocaleDateString(\"en-US\", {\n    year: \"numeric\",\n    month: \"long\",\n    day: \"numeric\",\n  });\n}\n\n<let/value=[] as { year: number; month: number; day: number }[]/>\n\n<Field class=\"mx-auto w-44\">\n  <FieldLabel for=\"date-picker-simple\">Date</FieldLabel>\n  <Popover class=\"w-auto p-0\">\n    <@trigger|props|>\n      <Button type=\"button\" ...props variant=\"outline\" id=\"date-picker-simple\" class=\"justify-start font-normal\">\n        <if=value[0]>\n          ${formatDate(value[0])}\n        </if>\n        <else>\n          <span>Pick a date</span>\n        </else>\n      </Button>\n    </@trigger>\n    <Calendar\n      value=value\n      valueChange=(next) => { value = next; }\n    />\n  </Popover>\n</Field>","description":"The upstream composition — `Popover` + `Calendar` wired together by hand instead of the all-in-one `DatePicker`."},{"id":"date-picker-range","title":"Range Picker","source":"import Field from \"@marko-ui/shadcn/ui/field/field.marko\";\nimport FieldLabel from \"@marko-ui/shadcn/ui/field/field-label.marko\";\nimport Popover from \"@marko-ui/shadcn/ui/popover/popover.marko\";\nimport Button from \"@marko-ui/shadcn/ui/button/button.marko\";\nimport Calendar from \"@marko-ui/shadcn/ui/calendar/calendar.marko\";\nimport Icon from \"@marko-ui/shadcn/ui/icon/icon.marko\";\n\nstatic function formatDate(date: { year: number; month: number; day: number }) {\n  return new Date(date.year, date.month - 1, date.day).toLocaleDateString(\"en-US\", {\n    year: \"numeric\",\n    month: \"short\",\n    day: \"2-digit\",\n  });\n}\n\n<const/fromDate={ year: 2026, month: 1, day: 20 }/>\n<const/toDate={ year: 2026, month: 2, day: 9 }/>\n\n<let/value=[fromDate, toDate]/>\n\n<Field class=\"mx-auto w-60\">\n  <FieldLabel for=\"date-picker-range\">Date Picker Range</FieldLabel>\n  <Popover class=\"w-auto p-0\">\n    <@trigger|props|>\n      <Button type=\"button\" ...props variant=\"outline\" id=\"date-picker-range\" class=\"justify-start px-2.5 font-normal\">\n        <Icon name=\"Calendar\" data-icon=\"inline-start\"/>\n        <if=value[0]>\n          <if=value[1]>\n            ${formatDate(value[0])} - ${formatDate(value[1])}\n          </if>\n          <else>\n            ${formatDate(value[0])}\n          </else>\n        </if>\n        <else>\n          <span>Pick a date</span>\n        </else>\n      </Button>\n    </@trigger>\n    <Calendar\n      selectionMode=\"range\"\n      numOfMonths=2\n      value=value\n      valueChange=(next) => { value = next; }\n    />\n  </Popover>\n</Field>","description":"`Calendar selectionMode=\"range\"` with `numOfMonths={2}` for selecting a date range across two visible months."},{"id":"date-picker-dob","title":"Date of Birth","source":"import Field from \"@marko-ui/shadcn/ui/field/field.marko\";\nimport FieldLabel from \"@marko-ui/shadcn/ui/field/field-label.marko\";\nimport Popover from \"@marko-ui/shadcn/ui/popover/popover.marko\";\nimport Button from \"@marko-ui/shadcn/ui/button/button.marko\";\nimport Calendar from \"@marko-ui/shadcn/ui/calendar/calendar.marko\";\n\n<let/open=false/>\n<let/value=[] as { year: number; month: number; day: number }[]/>\n\n<Field class=\"mx-auto w-44\">\n  <FieldLabel for=\"date\">Date of birth</FieldLabel>\n  <Popover open=open openChange=(next) => { open = next; } class=\"w-auto overflow-hidden p-0\">\n    <@trigger|props|>\n      <Button type=\"button\" ...props variant=\"outline\" id=\"date\" class=\"justify-start font-normal\">\n        <if=value[0]>\n          ${new Date(value[0].year, value[0].month - 1, value[0].day).toLocaleDateString()}\n        </if>\n        <else>\n          Select date\n        </else>\n      </Button>\n    </@trigger>\n    <Calendar\n      captionLayout=\"dropdown\"\n      value=value\n      valueChange=(next) => {\n        value = next;\n        open = false;\n      }\n    />\n  </Popover>\n</Field>","description":"`Calendar captionLayout=\"dropdown\"` swaps the month/year label for native `<select>`s, and the popover closes itself once a date is picked."},{"id":"date-picker-input","title":"Input","source":"import Field from \"@marko-ui/shadcn/ui/field/field.marko\";\nimport FieldLabel from \"@marko-ui/shadcn/ui/field/field-label.marko\";\nimport InputGroup from \"@marko-ui/shadcn/ui/input-group/input-group.marko\";\nimport InputGroupInput from \"@marko-ui/shadcn/ui/input-group/input.marko\";\nimport InputGroupAddon from \"@marko-ui/shadcn/ui/input-group/addon.marko\";\nimport InputGroupButton from \"@marko-ui/shadcn/ui/input-group/button.marko\";\nimport Popover from \"@marko-ui/shadcn/ui/popover/popover.marko\";\nimport Calendar from \"@marko-ui/shadcn/ui/calendar/calendar.marko\";\nimport Icon from \"@marko-ui/shadcn/ui/icon/icon.marko\";\n\nstatic function formatDate(date?: { year: number; month: number; day: number }) {\n  if (!date) return \"\";\n  return new Date(date.year, date.month - 1, date.day).toLocaleDateString(\"en-US\", {\n    day: \"2-digit\",\n    month: \"long\",\n    year: \"numeric\",\n  });\n}\n\nstatic function parseInput(text: string) {\n  const date = new Date(text);\n  if (isNaN(date.getTime())) return undefined;\n  return { year: date.getFullYear(), month: date.getMonth() + 1, day: date.getDate() };\n}\n\n<const/initial=(parseInput(\"2025-06-01\")!)/>\n\n<let/open=false/>\n<let/value=[initial]/>\n<let/text=formatDate(initial)/>\n\n<Field class=\"mx-auto w-48\">\n  <FieldLabel for=\"date-required\">Subscription Date</FieldLabel>\n  <InputGroup>\n    <InputGroupInput\n      id=\"date-required\"\n      value=text\n      placeholder=\"June 01, 2025\"\n      valueChange=(next) => {\n        text = next ?? \"\";\n        const parsed = parseInput(text);\n        if (parsed) value = [parsed];\n      }\n      onKeyDown(event: KeyboardEvent) {\n        if (event.key === \"ArrowDown\") {\n          event.preventDefault();\n          open = true;\n        }\n      }\n    />\n    <InputGroupAddon align=\"inline-end\">\n      <Popover open=open openChange=(next) => { open = next; } class=\"w-auto overflow-hidden p-0\">\n        <@trigger|props|>\n          <InputGroupButton ...props id=\"date-picker\" variant=\"ghost\" size=\"icon-xs\" aria-label=\"Select date\">\n            <Icon name=\"Calendar\"/>\n            <span class=\"sr-only\">Select date</span>\n          </InputGroupButton>\n        </@trigger>\n        <Calendar\n          value=value\n          valueChange=(next) => {\n            value = next;\n            text = formatDate(next[0]);\n            open = false;\n          }\n        />\n      </Popover>\n    </InputGroupAddon>\n  </InputGroup>\n</Field>","description":"An `InputGroup` text field kept in sync with a `Calendar` behind a popover trigger button."},{"id":"date-picker-time","title":"Time Picker","source":"import FieldGroup from \"@marko-ui/shadcn/ui/field/field-group.marko\";\nimport Field from \"@marko-ui/shadcn/ui/field/field.marko\";\nimport FieldLabel from \"@marko-ui/shadcn/ui/field/field-label.marko\";\nimport TextInput from \"@marko-ui/shadcn/ui/input/input.marko\";\nimport Popover from \"@marko-ui/shadcn/ui/popover/popover.marko\";\nimport Button from \"@marko-ui/shadcn/ui/button/button.marko\";\nimport Calendar from \"@marko-ui/shadcn/ui/calendar/calendar.marko\";\nimport Icon from \"@marko-ui/shadcn/ui/icon/icon.marko\";\n\nstatic function formatDate(date?: { year: number; month: number; day: number }) {\n  if (!date) return undefined;\n  return new Date(date.year, date.month - 1, date.day).toLocaleDateString(\"en-US\", {\n    year: \"numeric\",\n    month: \"long\",\n    day: \"numeric\",\n  });\n}\n\n<let/open=false/>\n<let/value=[] as { year: number; month: number; day: number }[]/>\n\n<FieldGroup class=\"mx-auto max-w-xs flex-row\">\n  <Field>\n    <FieldLabel for=\"date-picker-optional\">Date</FieldLabel>\n    <Popover open=open openChange=(next) => { open = next; } class=\"w-auto overflow-hidden p-0\">\n      <@trigger|props|>\n        <Button type=\"button\" ...props variant=\"outline\" id=\"date-picker-optional\" class=\"w-32 justify-between font-normal\">\n          <if=value[0]>\n            ${formatDate(value[0])}\n          </if>\n          <else>\n            Select date\n          </else>\n          <Icon name=\"ChevronDown\" data-icon=\"inline-end\"/>\n        </Button>\n      </@trigger>\n      <Calendar\n        captionLayout=\"dropdown\"\n        value=value\n        valueChange=(next) => {\n          value = next;\n          open = false;\n        }\n      />\n    </Popover>\n  </Field>\n  <Field class=\"w-32\">\n    <FieldLabel for=\"time-picker-optional\">Time</FieldLabel>\n    <TextInput\n      type=\"time\"\n      id=\"time-picker-optional\"\n      step=\"1\"\n      value=\"10:30:00\"\n      class=\"appearance-none bg-background [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none\"\n    />\n  </Field>\n</FieldGroup>","description":"A date `Popover`/`Calendar` pair alongside a plain `<input type=\"time\">` — there's no separate time-picker component upstream either."},{"id":"date-picker-value","title":"With value","source":"import DatePicker from \"@marko-ui/shadcn/ui/date-picker/date-picker.marko\";\n\n<DatePicker value=\"2026-08-10\"/>","description":"Pass `value` as an ISO date string (`YYYY-MM-DD`) to preselect a date."},{"id":"date-picker-controlled","title":"Controlled","source":"import DatePicker from \"@marko-ui/shadcn/ui/date-picker/date-picker.marko\";\n\n<let/value=\"2026-08-10\"/>\n\n<div class=\"flex items-center gap-4\">\n  <DatePicker\n    value=value\n    valueChange=(next) => { value = next ?? \"\"; }\n  />\n  <span class=\"text-sm text-muted-foreground\">value: ${value || \"none\"}</span>\n</div>","description":"Zag machines are controlled: a `value` prop without a change handler never moves. Pair it with `valueChange`, which receives the new ISO string (or `undefined` when cleared).","essential":true},{"id":"date-picker-disabled","title":"Disabled","source":"import DatePicker from \"@marko-ui/shadcn/ui/date-picker/date-picker.marko\";\n\n<DatePicker disabled/>","description":"A disabled date picker is skipped by the tab order and ignores pointer input."},{"id":"date-picker-read-only","title":"Read-only","source":"import DatePicker from \"@marko-ui/shadcn/ui/date-picker/date-picker.marko\";\n\n<DatePicker readOnly value=\"2026-08-10\"/>","description":"A read-only date picker shows its value but the calendar cannot change it."},{"id":"date-picker-locale","title":"Custom locale","source":"import DatePicker from \"@marko-ui/shadcn/ui/date-picker/date-picker.marko\";\n\n<DatePicker locale=\"fr-FR\"/>","description":"Pass a BCP 47 `locale` to localize month names, weekday labels, and formatting."},{"id":"date-picker-rtl","title":"RTL","source":"import DatePicker from \"@marko-ui/shadcn/ui/date-picker/date-picker.marko\";\n\n<div dir=\"rtl\">\n  <DatePicker placeholder=\"اختر تاريخًا\" class=\"w-[212px]\"/>\n</div>","description":"Set `dir=\"rtl\"` on a wrapping element (matching the surrounding document direction); the trigger icon and positioner flip automatically."}],"importInstallCommand":"bun add @marko-ui/shadcn marko-zag","nativeAttributes":"div","composition":"`<DatePicker>` is a complete, self-contained field (input + trigger + calendar) built on `@zag-js/date-picker` — reach for it first. For anything it doesn't cover (a date range, a dropdown month/year caption, syncing a free-text input), compose `Popover` and `Calendar` directly, the same way upstream does:\n\n```text\nPopover\n├── @trigger (render-prop)\n└── (body)\n    └── Calendar\n```\n\n`Popover`'s `@trigger` receives the machine's trigger props to spread onto any element (a `Button`, an `InputGroupButton`…), and the tag's own body holds whatever should render inside the positioned panel — typically a `Calendar`. See the Popover and Calendar pages for their full APIs."}
