v1.0.0

<bmx-date-picker>

A date typed into a field or chosen from a calendar, one date or a range, with named presets and an optional time.

29 properties · 3 events · 7 methods · 12 parts

Example

Show markup
<div class="row">
  <bmx-date-picker label="Start date" description="Type it, or press Down to open the calendar. The field order follows the page's locale."></bmx-date-picker>
</div>
<div class="row">
  <bmx-date-picker id="ex-date-stay" label="Stay" range="true" description="Two clicks. Clicking a date before the start begins again rather than inverting the range."></bmx-date-picker>
</div>
<div class="row">
  <bmx-date-picker id="ex-date-appt" label="Appointment" with-time="true" min="2026-01-01" description="Weekends are unavailable, and the time comes from a native field."></bmx-date-picker>
</div>
<script type="module">
  await customElements.whenDefined('bmx-date-picker');

  // `presets` is an array and `disabled-days-of-week` is one too — both are
  // properties, because neither fits in an attribute.
  document.getElementById('ex-date-stay').presets = [
    { label: 'This weekend', value: ['2026-09-12', '2026-09-13'] },
    { label: 'Next week', value: ['2026-09-14', '2026-09-20'] },
  ];

  document.getElementById('ex-date-appt').disabledDaysOfWeek = [0, 6];
</script>

WHY IT DOES NOT COMPOSE bmx-input

It should. The field is bmx-input's field, the masking is core/mask.ts, and putting one component inside the other is the story the rest of this library tells. It cannot, and the reason is the same one that shaped bmx-radio-group and bmx-select: the input has to carry aria-controls and aria-activedescendant pointing at the calendar, and an IDREF cannot cross a shadow boundary. Nested inside bmx-input's shadow root, the input would be referring to ids it cannot see - a combobox announced as controlling nothing, which looks entirely correct on screen.

So the field is its own, and what is shared is shared as code: the chrome from field-chrome.tsx, the caret arithmetic from core/mask.ts, the surface from overlay-surface.ts. The one thing knowingly not carried across from bmx-input is its undo-stack preservation, which is twenty lines of execCommand for a ten-character field; when a second component needs it, it should be extracted rather than copied.

DATES ARE NOT Dates

Not one Date object crosses into this component. src/core/calendar.ts works on { year, month, day } because new Date('2026-03-29') is the 28th in Honolulu, adding a day across a spring-forward lands on the day it started, and new Date(2026, 1, 31) is the 3rd of March. Every one of those is a booking on the wrong day that looks perfectly fine in testing.

THE LOCALE DECIDES MORE THAN THE MONTH NAMES

It decides the order of the typed fields, and that is the one that does damage: 09/05/2026 is the 9th of May in London and the 5th of September in New York, and both are real dates - so reading it wrong does not throw, it books the wrong day. The order comes from Intl.DateTimeFormat.formatToParts and the mask is built from it, so the placeholder, the mask and the parser can never disagree.

A bare en is not neutral: Intl resolves it to US conventions, so a page that declares lang="en" gets month/day/year whatever its author intended. Host pages meant for the UK must say en-GB.

The first day of the week comes from Intl.Locale's week info where the browser has it and falls back to Monday, the ISO 8601 week start, where it does not. first-day-of-week is the escape hatch for a consumer who cannot wait for a browser.

A KNOWN LIMIT, DELIBERATELY

In range mode the field is read-only and the calendar does the choosing. A masked two-date field with a separator is four times the parsing for a case people overwhelmingly use the calendar for, and the honest upgrade is two fields rather than one cleverer one. Recorded here so it is a decision rather than something nobody noticed.

Properties

PropertyAttributeTypeDefaultDescription
appearance appearance BmxDatePickerAppearance 'outline' Visual treatment.
autoFocus auto-focus boolean false Focus the field once it has rendered.
description description string Help text below the field.
disabled disabled boolean false Disable the field.
disabledDates disabled-dates string[] | string [] Individual dates that cannot be chosen, as YYYY-MM-DD. Accepts a comma-separated or JSON string as well - a bank-holiday list written by a server-side template is the case this exists for. See the note on disabledDaysOfWeek for why the type says | string.
disabledDaysOfWeek disabled-days-of-week number[] | string [] Days of the week that can never be chosen. Sunday is 0. Accepts a comma-separated or JSON string as well. The | string in the type is not decoration: without it Stencil observes this prop under its own camelCase name, which the HTML parser lowercases, so disabled-days-of-week would not exist as an attribute at all. See src/core/markup.ts.
errorText error-text string An error supplied by the consumer.
firstDayOfWeek first-day-of-week number Override the first day of the week. Sunday is 0.
fullWidth full-width boolean false Stretch to the width of the container.
hideLabel hide-label boolean false Hide the label visually while keeping it as the accessible name.
isDateUnavailable property only (iso: string) => boolean A consumer's own rule, asked after the others.
label label string The field's label. Required unless the label slot is used.
locale locale string The locale to write dates in. Defaults to the document's.
max max string The latest date that may be chosen, as YYYY-MM-DD.
messages property only BmxFieldMessages Replacements for the default wording, by reason. Accepts the JSON spelling of the object as well, for templates that can only write attributes. See src/core/markup.ts.
min min string The earliest date that may be chosen, as YYYY-MM-DD.
name name string The field's name in the form it belongs to.
placement placement BmxPlacement 'bottom-start' Which side the calendar opens on when there is room.
presets property only BmxDatePreset[] [] Named shortcuts, shown beside the calendar. Accepts the JSON spelling of the list as well, because an attribute is the only channel some templates have. See src/core/markup.ts.
range range boolean false Choose two dates rather than one.
readonly readonly boolean false Make the field read-only. It still submits and is still focusable.
required required boolean false Require a date before the form will submit.
shape shape BmxShape 'rounded' Corner treatment.
size size BmxSize 'md' Size step.
tone tone BmxTone 'primary' Semantic colour role.
validateOn validate-on BmxValidateOn 'blur' When the field is willing to reveal a problem.
value value string | null null The chosen date as YYYY-MM-DD. Two-way: the component writes back to it.
values property only string[] [] Both ends in range mode, as YYYY-MM-DD. Two-way. Accepts a comma-separated or JSON string as well, because an attribute is the only channel some templates have. See src/core/markup.ts.
withTime with-time boolean false Add a time field under the calendar. The value becomes YYYY-MM-DDTHH:mm.

Events

EventDetailDescription
bmxChange BmxDatePickerChangeDetail Fired when the chosen date changes.
bmxOpenChange boolean Fired when the calendar opens or closes.
bmxValidityChange BmxDatePickerValidityDetail Fired whenever the resolved validity changes.

Methods

MethodSignatureDescription
checkValidity checkValidity() => Promise<boolean> Validate now and return whether the field passed, without revealing anything.
clear clear() => Promise<void> Empty the selection.
closeCalendar closeCalendar() => Promise<void> Close the calendar.
openCalendar openCalendar() => Promise<void> Open the calendar.
removeFocus removeFocus() => Promise<void> Remove focus from the field.
reportValidity reportValidity() => Promise<boolean> Validate, reveal any problem, and focus the field if it has one.
setFocus setFocus(options?: FocusOptions) => Promise<void> Focus the field.

Slots

SlotDescription
(default) The default slot
description Rich help text, in place of the description property.
label Rich label content, in place of the label property.

CSS shadow parts

PartDescription
calendar The floating surface.
control The text input carrying role="combobox".
day One day cell.
description The help text.
error The error message.
field The bordered box.
grid The role="grid" of days.
header The month name and the paging buttons.
label The label element.
preset One named shortcut.
time The time field, with with-time.
trigger The button that opens the calendar.

CSS custom properties

PropertyDescription
--bmx-date-background The field's background. Set by appearance.
--bmx-date-border-color The field's border colour at rest.
--bmx-date-border-width Border width of the field.
--bmx-date-calendar-background The floating calendar's background.
--bmx-date-calendar-shadow The calendar's shadow.
--bmx-date-cell-radius Corner radius of a day.
--bmx-date-cell-size The width and height of one day.
--bmx-date-font-size The typed date's font size.
--bmx-date-height The field's height.
--bmx-date-label-font-size The label's font size.
--bmx-date-padding-inline Horizontal padding inside the field.
--bmx-date-radius Corner radius of the field and the calendar.
--bmx-date-range-background The days between the two ends of a range.
--bmx-date-selected-background A chosen day. Defaults to the tone's solid colour.
--bmx-date-support-font-size Font size of the description and error message.
--bmx-date-today-color The marker under today's date.