Skip to content

DatePicker ​

A date picker is two inputs in one: a segmented field that can be typed into, and a calendar for picking. Neither is a fallback for the other — typing is faster for a date you know, and the calendar is faster for one you are choosing.

ts
import { DatePicker, DatePickerGroup, DatePickerInput } from "ropav";

The field and the calendar ​

DatePickerInput renders one DatePickerSegment per part of the date, in the order the reader's locale writes them. DatePickerPopover holds a Calendar, which is a component in its own right.

Date
date-picker-basic.vue
vue
<script setup lang="ts">
import {
  Calendar,
  CalendarCell,
  CalendarGrid,
  CalendarGridBody,
  CalendarGridHeader,
  CalendarHeader,
  CalendarHeaderCell,
  CalendarNavButton,
  DatePicker,
  DatePickerGroup,
  DatePickerInput,
  DatePickerPopover,
  DatePickerSegment,
  DatePickerSuffix,
  DatePickerTrigger,
  DatePickerTriggerIndicator,
  Label,
} from "ropav";
</script>

<template>
  <div class="field">
    <DatePicker name="date">
      <Label>Date</Label>

      <DatePickerGroup full-width>
        <DatePickerInput>
          <template #default="{ segment }">
            <DatePickerSegment :segment />
          </template>
        </DatePickerInput>
        <DatePickerSuffix>
          <DatePickerTrigger>
            <DatePickerTriggerIndicator />
          </DatePickerTrigger>
        </DatePickerSuffix>
      </DatePickerGroup>

      <DatePickerPopover>
        <Calendar aria-label="Selected date">
          <CalendarHeader>
            <CalendarNavButton slot="previous" />
            <CalendarNavButton slot="next" />
          </CalendarHeader>
          <CalendarGrid>
            <CalendarGridHeader>
              <template #default="{ day }">
                <CalendarHeaderCell>{{ day }}</CalendarHeaderCell>
              </template>
            </CalendarGridHeader>
            <CalendarGridBody>
              <template #default="{ date }">
                <CalendarCell :date />
              </template>
            </CalendarGridBody>
          </CalendarGrid>
        </Calendar>
      </DatePickerPopover>
    </DatePicker>
  </div>
</template>

<style scoped>
/* The control renders two roots, so a scoped rule has nothing in it to attach to. The demo
   owns this box instead, and a column stretches the control across it. */
.field {
  display: flex;
  flex-direction: column;
  width: calc(var(--rp-spacing) * 72);
}
</style>

There is a lot of markup here, and that is the trade: every part is yours to place, so a picker with a year jump, a two-month calendar or a footer is composition rather than a prop.

Calendars other than Gregorian ​

A date picker builds a Gregorian calendar until it is told otherwise, which keeps the other systems out of the bundle for the projects that never need them. Passing a calendar system is what pulls it in — see Calendar systems.

Accessibility ​

  • The segments are one control: arrow keys change the segment under the cursor, left and right move between them, and typing digits fills them in.
  • The value is announced as a whole date, not as three numbers.
  • The popover traps focus while it is open and returns it to the field on close.

API ​

DatePicker

PropTypeDefaultDescription
ariaDescribedbystring—
ariaLabelstring—
ariaLabelledbystring—
autoCompletestring—What the browser may offer to autofill.
autoFocusboolean—Whether the first segment takes focus as the picker appears.
createCalendar((identifier: CalendarIdentifier) => Calendar)—Builds the calendar system for an identifier. Injectable so a build can ship fewer of them.
defaultOpenboolean—
defaultValueDateValue | null—The date the picker starts with while it owns its own value.
firstDayOfWeek"fri" | "mon" | "sat" | "sun" | "thu" | "tue" | "wed"—The day a week starts on in the calendar, when it should not follow the locale.
formstring—Id of the form the value belongs to, when it is not an ancestor.
granularity"day" | "hour" | "minute" | "second"—The smallest part of a date the picker shows. Taken from the value when unset.
hideTimeZoneboolean—Whether the time zone abbreviation is hidden.
hourCycle12 | 24—Whether to show a 12 or 24 hour clock. Taken from the locale when unset.
idstring—Id for the group around the segments and the trigger, which is what a label points at.
isDateUnavailable((date: DateValue) => boolean)—Rules a date out even though it is inside the range. A prop rather than an emit: the picker calls it while validating and while drawing the calendar, and an emit has no answer to give back.
isDisabledboolean—
isInvalidboolean—Whether the picker reads as invalid regardless of what it holds.
isOpenboolean—Whether the popover is open. Set this and the caller owns it.
isReadOnlyboolean—
isRequiredboolean—
localestring—Overrides the locale in force, for a picker that must not follow its surroundings.
maxValueDateValue | null—
minValueDateValue | null—
namestring—Name the value is submitted under.
pageBehavior"single" | "visible""visible"How much the calendar moves by when it pages.
placeholderValueDateValue | null—A date whose shape the empty segments follow, which is also where the calendar opens. Defaults to today.
shouldCloseOnSelectboolean | (() => boolean)trueWhether picking a date closes the popover.
shouldForceLeadingZerosboolean—Whether numbers are always padded to two digits. Taken from the locale when unset.
validate((value: DateValue | null) => string | true | string[] | null | undefined)—Extra rule the value has to satisfy, beyond the range.
validationBehavior"aria" | "native""native"Whether errors go through the browser or through ARIA alone.
valueDateValue | null—The date the picker shows. Set this and the caller owns the value.

The default slot receives:

Slot propType
isDisabledboolean
isInvalidboolean
isOpenboolean
isReadOnlyboolean
isRequiredboolean
EventPayload
changeDateValue | null
focusChangeboolean
openChangeboolean
update:isOpenboolean
update:valueDateValue | null

DatePickerPopover

PropTypeDefaultDescription
containerPaddingnumber—Distance kept between the popover and the edge of the viewport.
crossOffsetnumber—Distance along the cross axis.
isKeyboardDismissDisabledbooleanfalse
offsetnumber—Distance along the main axis, between the popover and the group.
placement"bottom" | "bottom end" | "bottom left" | "bottom right" | "bottom start" | "end" | "end bottom" | "end top" | "left" | "left bottom" | "left top" | "right" | "right bottom" | "right top" | "start" | "start bottom" | "start top" | "top" | "top end" | "top left" | "top right" | "top start""bottom"Where the popover sits relative to the group.
shouldFlipboolean—Whether the popover may flip to the other side when it does not fit.

Slots: default.

DatePickerTrigger

Slots: default.

DatePickerTriggerIndicator

Slots: default.