Skip to main content
On this pageFunctions

Ui/DatePicker

Functions

clear

functionsource
/** Programmatically clears the selected date. */
(model: DatePicker.Model): UpdateReturn

close

functionsource
/** Programmatically closes the date picker. Use this in domain-event handlers. */
(model: DatePicker.Model): UpdateReturn

init

functionsource
/**
 * Creates an initial date picker model from a config. The calendar and
 * popover submodels are created with derived ids so their DOM elements stay
 * addressable. The popover is opened in `contentFocus` mode so focus lands on
 * the calendar grid instead of the panel.
 */
(config: InitConfig): DatePicker.Model

open

functionsource
/**
 * Programmatically opens the date picker, updating the model and returning
 * focus and popover commands. Use this in domain-event handlers.
 */
(model: DatePicker.Model): UpdateReturn

selectDate

functionsource
/** Programmatically selects a date, committing it and closing the popover. Emits a `SelectedDate` OutMessage just like a user-initiated selection. */
(
  model: DatePicker.Model,
  date: {
    day: number
    month: number
    year: number
  }
): UpdateReturn

update

functionsource

Types

InitConfig

typesource
/** Configuration for creating a date picker model with `init`. */
type InitConfig = Readonly<{
  disabledDates: ReadonlyArray<CalendarDate>
  disabledDaysOfWeek: ReadonlyArray<Calendar.DayOfWeek>
  id: string
  initialSelectedDate: CalendarDate
  isAnimated: boolean
  locale: Calendar.LocaleConfig
  maxDate: CalendarDate
  minDate: CalendarDate
  today: CalendarDate
}>

ViewInputs

typesource
/**
 * Per-render view inputs passed to `view` via `h.submodel`'s `viewInputs` field.
 * 
 *  The DatePicker emits a `SelectedDate({ date })` OutMessage when the
 *  user commits a date. Consumers pattern-match this in their
 *  `GotDatePickerMessage` handler (third tuple element of
 *  `Ui.DatePicker.update`'s return) to lift the date into domain state.
 */
type ViewInputs = Readonly<{
  anchor: AnchorConfig
  attributes: ReadonlyArray<ChildAttribute>
  backdropAttributes: ReadonlyArray<ChildAttribute>
  backdropClassName: string
  className: string
  isDisabled: boolean
  name: string
  panelAttributes: ReadonlyArray<ChildAttribute>
  panelClassName: string
  toCalendarView: (attributes: UiCalendar.CalendarAttributes) => Html
  triggerAttributes: ReadonlyArray<ChildAttribute>
  triggerClassName: string
  triggerContent: (maybeDate: Option.Option<CalendarDate>) => Html
}>

Constants

ChangedViewMonth

constsource
/**
 * Emitted when the visible month changes (propagated from the embedded
 * Calendar). Useful for month-scoped data loading.
 */
const ChangedViewMonth: CallableTaggedStruct<"ChangedViewMonth", {
  month: Int
  year: Int
}>

Cleared

constsource
/** Sent when the user clears the selected date. Does not close the popover. */
const Cleared: CallableTaggedStruct<"Cleared", {}>

Closed

constsource
/**
 * Sent when the popover should close. Delegates to Popover which returns
 * focus to the trigger button.
 */
const Closed: CallableTaggedStruct<"Closed", {}>

GotCalendarMessage

constsource
/** Wraps a Calendar submodel message for delegation. */
const GotCalendarMessage: CallableTaggedStruct<"GotCalendarMessage", {
  message: Union<readonly [
    CallableTaggedStruct<"ClickedDay", {
      date: Struct<{
        day: Int
        month: Int
        year: Int
      }>
    }>,
    CallableTaggedStruct<"PressedKeyOnGrid", {
      isShift: Boolean
      key: String
    }>,
    CallableTaggedStruct<"ClickedPreviousMonthButton", {}>,
    CallableTaggedStruct<"ClickedNextMonthButton", {}>,
    CallableTaggedStruct<"ClickedHeading", {}>,
    CallableTaggedStruct<"SelectedMonth", {
      month: Int
    }>,
    CallableTaggedStruct<"SelectedYear", {
      year: Int
    }>,
    CallableTaggedStruct<"PagedYears", {
      direction: Literals<readonly [1, -1]>
    }>,
    CallableTaggedStruct<"FocusedGrid", {}>,
    CallableTaggedStruct<"BlurredGrid", {}>,
    CallableTaggedStruct<"RefreshedToday", {
      today: Struct<{
        day: Int
        month: Int
        year: Int
      }>
    }>,
    CallableTaggedStruct<"CompletedFocusGrid", {}>
  ]>
}>

GotPopoverMessage

constsource
/** Wraps a Popover submodel message for delegation. */
const GotPopoverMessage: CallableTaggedStruct<"GotPopoverMessage", {
  message: Union<[
    CallableTaggedStruct<"RequestedOpen", {}>,
    CallableTaggedStruct<"RequestedClose", {}>,
    CallableTaggedStruct<"BlurredPanel", {}>,
    CallableTaggedStruct<"PressedPointerOnButton", {
      button: Number
      pointerType: String
    }>,
    CallableTaggedStruct<"CompletedFocusPanel", {}>
  ]>
}>

Message

constsource
/** Union of all messages the date picker component can produce. */
const Message: S.Union<[typeof GotCalendarMessage, typeof GotPopoverMessage, typeof RequestedSelectDate, typeof Cleared, typeof Opened, typeof Closed]>

Model

constsource
/**
 * Schema for the date picker component's state. Holds the selected date,
 * the embedded Calendar submodel (the visible grid), and the embedded Popover
 * submodel (the open/close + transition layer).
 */
const Model: Struct<{
  calendar: Struct<{
    disabledDates: $Array<Struct<{
      day: Int
      month: Int
      year: Int
    }>>
    disabledDaysOfWeek: $Array<Literals<readonly ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]>>
    id: String
    isGridFocused: Boolean
    locale: Struct<{
      dayNames: Tuple<readonly [String, String, String, String, String, String, String]>
      firstDayOfWeek: Literals<readonly ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]>
      monthNames: Tuple<readonly [String, String, String, String, String, String, String, String, String, String, String, String]>
      shortDayNames: Tuple<readonly [String, String, String, String, String, String, String]>
      shortMonthNames: Tuple<readonly [String, String, String, String, String, String, String, String, String, String, String, String]>
    }>
    maybeFocusedDate: Option<Struct<{
      day: Int
      month: Int
      year: Int
    }>>
    maybeMaxDate: Option<Struct<{
      day: Int
      month: Int
      year: Int
    }>>
    maybeMinDate: Option<Struct<{
      day: Int
      month: Int
      year: Int
    }>>
    maybeSelectedDate: Option<Struct<{
      day: Int
      month: Int
      year: Int
    }>>
    today: Struct<{
      day: Int
      month: Int
      year: Int
    }>
    viewMode: Literals<readonly ["Days", "Months", "Years"]>
    viewMonth: Int
    viewYear: Int
  }>
  id: String
  maybeSelectedDate: Option<Struct<{
    day: Int
    month: Int
    year: Int
  }>>
  popover: Struct<{
    animation: Struct<{
      id: String
      isShowing: Boolean
      transitionState: Literals<readonly ["Idle", "EnterStart", "EnterAnimating", "LeaveStart", "LeaveAnimating"]>
    }>
    contentFocus: Boolean
    id: String
    isAnimated: Boolean
    isModal: Boolean
    isOpen: Boolean
    maybeLastButtonPointerType: Option<String>
  }>
}>

Opened

constsource
/**
 * Sent when the popover should open. Triggers focus-grid on the embedded
 * Calendar so keyboard focus lands inside the grid instead of the panel.
 */
const Opened: CallableTaggedStruct<"Opened", {}>

OutMessage

constsource
/** Union of out-messages the date picker can produce. */
const OutMessage: Union<readonly [
  CallableTaggedStruct<"ChangedViewMonth", {
    month: Int
    year: Int
  }>,
  CallableTaggedStruct<"SelectedDate", {
    date: Struct<{
      day: Int
      month: Int
      year: Int
    }>
  }>
]>

RequestedSelectDate

constsource
/**
 * Sent when the user commits a date via click or keyboard. Updates the
 * selected date, syncs the calendar, and closes the popover.
 */
const RequestedSelectDate: CallableTaggedStruct<"RequestedSelectDate", {
  date: Struct<{
    day: Int
    month: Int
    year: Int
  }>
}>

SelectedDate

constsource
/**
 * Emitted when the user commits a date selection (propagated from the
 * embedded Calendar). The popover has already closed; the parent reads the
 * committed date and lifts it into domain state.
 */
const SelectedDate: CallableTaggedStruct<"SelectedDate", {
  date: Struct<{
    day: Int
    month: Int
    year: Int
  }>
}>

reflectDisabledDates

constsource
/**
 * Reflects the list of individually-disabled dates onto the embedded
 * calendar. Pass an empty array to clear. Does NOT reconcile the current
 * selection.
 */
const reflectDisabledDates: Reflect<Model, ReadonlyArray<CalendarDate>>

reflectDisabledDaysOfWeek

constsource
/**
 * Reflects the days of the week that are disabled onto the embedded calendar
 * (e.g. weekends). Pass an empty array to clear. Does NOT reconcile the
 * current selection.
 */
const reflectDisabledDaysOfWeek: Reflect<Model, ReadonlyArray<Calendar.DayOfWeek>>

reflectMaxDate

constsource
/**
 * Reflects the maximum selectable date onto the embedded calendar. Pass
 * `Option.none()` to remove the maximum. Does NOT reconcile the current
 * selection.
 */
const reflectMaxDate: Reflect<Model, Option.Option<CalendarDate>>

reflectMinDate

constsource
/**
 * Reflects the minimum selectable date onto the embedded calendar. Pass
 * `Option.none()` to remove the minimum. Use this when the minimum derives
 * from other Model state (e.g. a start date field whose current selection
 * constrains an end date picker).
 * 
 * Does NOT reconcile the current selection. If a previously-selected date
 * is now below the new minimum, it remains selected. Callers should `clear`
 * or reassign the selection explicitly if their domain requires it.
 */
const reflectMinDate: Reflect<Model, Option.Option<CalendarDate>>

reflectSelectedDate

constsource
/**
 * Reflects an externally-sourced selected date onto the date picker
 *  without emitting an OutMessage or touching the popover. Sets the
 *  picker's selection and reflects it onto the embedded calendar (moving
 *  the calendar's view to the date), mirroring `selectDate`'s state change
 *  minus the `SelectedDate` announcement and the popover close. Pass
 *  `Option.none()` to clear. Use this to mirror external truth (a URL
 *  parameter, a saved draft) onto the picker. Contrast with `selectDate`,
 *  a user or programmatic *choice* that emits `SelectedDate`. Returns the
 *  model directly because it produces no commands and no OutMessage.
 */
const reflectSelectedDate: Reflect<Model, Option.Option<CalendarDate>>

view

constsource
/**
 * Renders an accessible date picker: a trigger button that opens a popover
 * containing an accessible calendar grid. The date picker assembles the
 * embedded Calendar and Popover components into one flat API. Consumers
 * provide the trigger face and the calendar grid layout, DatePicker handles
 * focus choreography, open/close state, and form submission.
 */
const view: SubmodelView<DatePicker.Model, {
  _tag: "Closed"
} | {
  _tag: "Opened"
} | {
  _tag: "GotCalendarMessage"
  message: {
    _tag: "ClickedDay"
    date: {
      day: number
      month: number
      year: number
    }
  } | {
    _tag: "PressedKeyOnGrid"
    isShift: boolean
    key: string
  } | {
    _tag: "ClickedPreviousMonthButton"
  } | {
    _tag: "ClickedNextMonthButton"
  } | {
    _tag: "ClickedHeading"
  } | {
    _tag: "SelectedMonth"
    month: number
  } | {
    _tag: "SelectedYear"
    year: number
  } | {
    _tag: "PagedYears"
    direction: -1 | 1
  } | {
    _tag: "FocusedGrid"
  } | {
    _tag: "BlurredGrid"
  } | {
    _tag: "RefreshedToday"
    today: {
      day: number
      month: number
      year: number
    }
  } | {
    _tag: "CompletedFocusGrid"
  }
} | {
  _tag: "GotPopoverMessage"
  message: {
    _tag: "CompletedLockScroll"
  } | {
    _tag: "CompletedUnlockScroll"
  } | {
    _tag: "CompletedInertOthers"
  } | {
    _tag: "CompletedRestoreInert"
  } | {
    _tag: "CompletedFocusButton"
  } | {
    _tag: "IgnoredMouseClick"
  } | {
    _tag: "SuppressedSpaceScroll"
  } | {
    _tag: "RequestedOpen"
  } | {
    _tag: "RequestedClose"
  } | {
    _tag: "BlurredPanel"
  } | {
    _tag: "PressedPointerOnButton"
    button: number
    pointerType: string
  } | {
    _tag: "CompletedFocusPanel"
  } | {
    _tag: "CompletedAnchorPopover"
  } | {
    _tag: "CompletedPortalPopoverBackdrop"
  } | {
    _tag: "GotAnimationMessage"
    message: {
      _tag: "Showed"
    } | {
      _tag: "Hid"
    } | {
      _tag: "AdvancedAnimationFrame"
    } | {
      _tag: "EndedAnimation"
    }
  }
} | {
  _tag: "RequestedSelectDate"
  date: {
    day: number
    month: number
    year: number
  }
} | {
  _tag: "Cleared"
}, Readonly<{
  anchor: {
    gap: number
    offset: number
    padding: number
    placement: "bottom" | "left" | "right" | "top" | "top-start" | "top-end" | "right-start" | "right-end" | "bottom-start" | "bottom-end" | "left-start" | "left-end"
    portal: boolean
  }
  attributes: readonly Array<Readonly<{
    __childAttribute: true
    attribute: unknown
    dispatch: DispatchSync
  }>>
  backdropAttributes: readonly Array<Readonly<{
    __childAttribute: true
    attribute: unknown
    dispatch: DispatchSync
  }>>
  backdropClassName: string
  className: string
  isDisabled: boolean
  name: string
  panelAttributes: readonly Array<Readonly<{
    __childAttribute: true
    attribute: unknown
    dispatch: DispatchSync
  }>>
  panelClassName: string
  toCalendarView: (attributes: CalendarAttributes) => Html
  triggerAttributes: readonly Array<Readonly<{
    __childAttribute: true
    attribute: unknown
    dispatch: DispatchSync
  }>>
  triggerClassName: string
  triggerContent: (maybeDate: Option<{
    day: number
    month: number
    year: number
  }>) => Html
}>>

Stay in the update loop.

New releases, patterns, and the occasional deep dive.


Built with Foldkit.

© 2026 Devin Jameson