Use a date picker when the interface benefits from visual date selection or date validation. If users need to enter very flexible freeform dates or work with a tiny, predictable set of choices, a simpler input or select may be more appropriate.
When to use
Use date pickers when
- Users need to select a specific date with high accuracy
- A calendar view makes the choice faster than typing
- You need to limit dates with min/max rules or disabled dates
- The task involves travel dates, appointments, deadlines, or availability
Do not use date pickers when
- The date can be entered more efficiently with a simple text field
- The range of valid dates is so small that a select or radio group is clearer
- Users need to enter partial, approximate, or highly flexible date values
- The interaction would be unnecessarily heavy for the task
Patterns
Anatomy
| Part | Element | Description |
|---|---|---|
| 1 | Label | Describes what date the field is asking for (label slot) |
| 2 | Date field | The input control people focus, type into, or use to open the calendar |
| 3 | Icon | The calendar affordance that signals date selection and panel access |
| 4 | Calendar | The panel surface that contains the date selection interface |
| 5 | Month and year control | The heading and navigation controls used to move through months and years |
| 6 | Week day | The abbreviated day-of-week labels that structure the calendar grid |
| 7 | Day | An individual selectable calendar day |
| 8 | Selected date | The currently chosen day or days shown with selected styling |
| 9 | Current day | Today’s date, highlighted to help people orient themselves in the calendar |
Design guidelines
Choose the simplest selection mode
Start with
single when one date is enough. Use range only when people need both a start and end date, and use multi only for truly non-consecutive selections.Keep labels and format expectations clear
Write labels that describe the task directly, such as “Arrival date” or “Travel dates”. Make sure the displayed format and first day of week match the product locale.
For
range and most multi scenarios, showing two months at once usually makes comparison easier and reduces selection errors.Usage
Default
Use the defaultsingle type when users need to choose one date. This is the best starting point for appointments, due dates, deadlines, and similar tasks.
Users can also enter a date manually. After pressing Tab, the component formats the value and reflects it in the calendar view.Supported input formats include:
- ISO format:
2024-05-30 - Text format:
30 May 2024,May 30, 2024,30 January 2024,January 1, 1970(locale-aware) - Numeric format:
30/05/2024,05-30-2024,30.05.2024,05.30.2024(with day/month heuristics)
Date range
Usetype="range" when users need a start and end date. Set months="2" so both months are visible in the panel and the interval is easier to understand.
Multiple dates
Usetype="multi" when users need to pick several non-consecutive dates. Unlike the single-date picker, the panel stays open while users continue selecting.
Options
Disabled
Usedisabled when the date field should not be interactive, such as when access is restricted based on user permissions or form state.
Validation states
Usevalidation-status when the field should show immediate visual feedback after validation.
Label with optional text
Use an optional indicator when the date adds context but is not required to complete the form.Label with info tooltip
Combine the label slot with a tooltip when users may need a short explanation before selecting a date.Without label
Use a label-less date picker only when the surrounding context already makes the purpose unmistakable, such as within a tightly scoped filter row or a grouped form layout.Locale
Uselocale to match date formatting and calendar conventions to regional expectations.
First day of week
Usefirst-day-of-week to align the calendar grid with regional or business expectations.
Show outside days
By default, the calendar shows only the days of the displayed month. Enableshow-outside-days when the additional context is helpful.
Disallowed dates
UseisDateDisallowed to make specific dates unavailable for selection. This is useful for holidays, sold-out inventory, blackout periods, or policy restrictions.
Custom display format
UseformatOptions when the selected date needs a more descriptive text format in the input field.
Best practices
DoUse clear, task-specific labels like “Arrival date” or “Travel dates” so users know exactly what they are selecting.
Don’tDo not overcomplicate the field label or ask for extra date information that the task does not need.
DoUse a single combined input when possible. It keeps the interaction simpler and easier to scan.
Don’tDo not split day, month, and year into separate inputs unless the use case truly requires it.
DoDisable unavailable dates when the business rules are known, instead of letting users submit invalid choices.
Don’tDo not rely on placeholder text as the only instruction or explanation for the field.
DoShow two months for range selection when comparison matters, so people can understand the interval more easily.
Don’tDo not use a heavier multi-date or range pattern when one simple date field would solve the task.
Accessibility
bq-date-pickeris form-associated and delegates focus, so it participates in native forms and moves focus into the internal<input>element when the component receives focus.- The input element sets
aria-disabled="true"whendisabledistrue, andaria-invalid="true"whenvalidationStatusis"error". - The input uses
aria-haspopup="dialog"andaria-controlsto announce the calendar panel to assistive technologies, andaria-describedbyto associate the visible label with the control when alabelslot is provided. - The calendar panel carries
role="dialog"andaria-modal="true", and is labelled viaaria-labelledbymatching the label slot — keeping the panel context announced correctly to screen reader users. - The component emits
bqFocus,bqBlur,bqChange, andbqClear, which give you the hooks needed to announce validation results, react to changes, and keep form state synchronized. - Keyboard users can open the calendar panel with
EnterorSpace, navigate days with the arrow keys, and close the panel withEscape. - Always provide a visible label through the
labelslot. Without it,aria-describedbyon the input has no target and the field loses its accessible name. - Validation states should never rely on color alone. Pair
validationStatuswith visible error text so screen reader users receive the same feedback as sighted users. - Keep
locale,first-day-of-week, and display formatting aligned with user expectations so typed input and visible values remain understandable for all users.
API reference
Properties
| Property | Attribute | Description | Type | Default |
|---|---|---|---|---|
autofocus | autofocus | If true, the input is focused on component render | boolean | undefined |
clearButtonLabel | clear-button-label | Accessible label for the clear button | string | "Clear value" |
disableClear | disable-clear | If true, the clear button is hidden | boolean | false |
disabled | disabled | Disables the date picker | boolean | false |
distance | distance | Gap between the panel and the input trigger | number | 8 |
firstDayOfWeek | first-day-of-week | First day of the week where Sunday is 0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 1 |
form | form | ID of the form the input belongs to | string | undefined |
formValidationMessage | form-validation-message | Native validation message used when required is set | string | undefined |
formatOptions | (property only) | Intl.DateTimeFormat options used for the displayed value | DateTimeFormatOptions | { day: 'numeric', month: 'short', year: 'numeric' } |
isDateDisallowed | (property only) | Function used to disable specific dates | (date: Date) => boolean | undefined |
locale | locale | Locale used to format and parse dates | Intl.LocalesArgument | "en-GB" |
max | max | Latest selectable date | string | undefined |
min | min | Earliest selectable date | string | undefined |
months | months | Number of months displayed for range and optionally multi | number | undefined |
monthsPerView | months-per-view | How navigation moves through months: one month or the full visible view | "single" | "months" | "single" |
name | name | Name of the underlying input | string | undefined |
open | open | If true, the calendar panel is visible | boolean | false |
panelHeight | panel-height | Overrides the panel height | string | "auto" |
placeholder | placeholder | Placeholder text | string | undefined |
placement | placement | Position of the calendar panel | "top" | "top-start" | "top-end" | "right" | "right-start" | "right-end" | "bottom" | "bottom-start" | "bottom-end" | "left" | "left-start" | "left-end" | "bottom-end" |
required | required | Marks the date picker as required | boolean | undefined |
showOutsideDays | show-outside-days | Shows days outside the current month | boolean | false |
skidding | skidding | Horizontal offset between panel and trigger | number | 0 |
strategy | strategy | Positioning strategy for the panel | "fixed" | "absolute" | "fixed" |
tentative | tentative | Tentative date used during range selection | string | undefined |
type | type | Selection mode | "single" | "range" | "multi" | "single" |
validationStatus | validation-status | Validation state of the control | "none" | "error" | "warning" | "success" | "none" |
value | value | Selected value in ISO-8601 format; range uses start/end, multi uses space-separated dates | string | undefined |
Events
| Event | Description | Type |
|---|---|---|
bqBlur | Fired when the input loses focus | CustomEvent<HTMLBqDatePickerElement> |
bqChange | Fired when the input value changes after typing, pasting, or selecting a date | CustomEvent<{ value: string; el: HTMLBqDatePickerElement }> |
bqClear | Fired when the value is cleared | CustomEvent<HTMLBqDatePickerElement> |
bqFocus | Fired when the input receives focus | CustomEvent<HTMLBqDatePickerElement> |
- In React, prefix events with
on:onBqBlur,onBqChange,onBqClear,onBqFocus. - In Angular, use the event binding syntax:
(bqBlur),(bqChange),(bqClear),(bqFocus). - In Vue, use the
@shorthand:@bqBlur,@bqChange,@bqClear,@bqFocus.
Methods
| Method | Description | Signature |
|---|---|---|
clear() | Clears the selected value | clear() => Promise<void> |
Slots
| Slot | Description |
|---|---|
label | Label content for the field |
prefix | Optional prefix content inside the control |
suffix | Optional suffix content inside the control |
clear-icon | Replaces the default clear icon |
Shadow parts
| Part | Description |
|---|---|
base | Base wrapper for the component |
button | Native HTML <button> element used inside the clear button |
control | Input control wrapper |
input | Native text input used under the hood |
label | Label slot container |
prefix | Prefix slot container |
suffix | Suffix slot container |
clear-btn | Clear button |
panel | Date picker panel container |
calendar__button | Calendar navigation and day buttons |
calendar__container | Calendar container |
calendar__day | Day cells in the calendar grid |
calendar__disabled | Disabled day buttons |
calendar__disallowed | Days disabled via isDateDisallowed |
calendar__head | Table header row |
calendar__header | Calendar header wrapper |
calendar__heading | Calendar month heading |
calendar__next | Next month button |
calendar__outside | Outside-month day cells |
calendar__previous | Previous month button |
calendar__range-end | Range end date |
calendar__range-inner | Dates inside a selected range |
calendar__range-start | Range start date |
calendar__selected | Selected day cells |
calendar__table | Calendar table element |
calendar__td | Calendar body cells |
calendar__th | Calendar header cells |
calendar__today | Today’s date cell |
calendar__tr | Calendar rows |
calendar__week | Week rows in the calendar body |
CSS custom properties
Resources
Interactive playground
Explore date picker variants, validation, locale, and panel behavior in Storybook.
Source code
Browse the component implementation, styles, and tests on GitHub.