Forms & inputs
Date Picker
Origin-aware popover with a spring landing
detent-date-picker
Port status
- Catalog status
- implemented
- Origin
- upstream
- Phase
- 3
- Wave
- phase-3-forms
- Group
- Forms & inputs
6.4 KB gzip for the class module
Variants
Open a picker and choose a date to see the event detail.
Recorded states
disabledrecorded state; no setterexpandedrecorded state; no setter
Usage
Import
import '/components/date-picker/define.js';
// or register it yourself
import { DetentDatePicker } from '/components/date-picker/date-picker.js';
Attributes
aligndefault-monthdefault-valuedisabledheightlocalemax-datemin-datenameopenplaceholderrangerequiredsidetextvalueweek-starts-on
Properties
valuedefaultValueplaceholderalignsidedisabledrangeheighttextlocaleweekStartsOnminDatemaxDatedefaultMonthisDateDisablednamerequiredopenonChange
Slots
default
Events
detent-change— { date: Date | null } or { range: { from, to } }detent-close— { reason: 'escape' | 'outside' }
Example
Runnable example: site/examples/date-picker.ts. The snippet below is generated from the catalogued attributes.
<detent-date-picker
align="start"
default-month
default-value
disabled
height
locale
max-date
min-date
name
open
placeholder="Pick a date' / 'Pick a range"
range
required
side="auto"
text
value
week-starts-on
></detent-date-picker>
Property-only values
const element = document.querySelector('detent-date-picker');
if (element !== null) {
// onChange: (date: Date | null) => void | (range: DateRange) => void
element.onChange = () => {};
}
Source
The pinned upstream source for this row:
src/components/ui/date-picker.tsxsha256 cd0d869892e0…
Native files
The native module and its artifacts:
src/components/date-picker/date-picker.tssrc/components/date-picker/styles.csssrc/components/date-picker/define.tsdocs/components/date-picker.mdsite/examples/date-picker.tstests/browser/date-picker.spec.tsevidence/components/date-picker.md
API
Boolean attributes follow HTML presence semantics: present means true, absent means false, and disabled="false" still means disabled.
Attributes
| Attribute | Property | Type | Default | Notes |
|---|---|---|---|---|
align | align | 'start' | 'end' | 'start' | Kebab-case attribute; camelCase property. |
default-month | — | — | — | Recorded in the catalog as an attribute. |
default-value | defaultValue | Date | null | DateRange | null | Kebab-case attribute; camelCase property. |
disabled | disabled | boolean | false | Presence semantics: present means true, absent means false. |
height | — | — | — | Recorded in the catalog as an attribute. |
locale | — | — | — | Recorded in the catalog as an attribute. |
max-date | — | — | — | Recorded in the catalog as an attribute. |
min-date | — | — | — | Recorded in the catalog as an attribute. |
name | — | — | — | Recorded in the catalog as an attribute. |
open | — | — | — | Recorded in the catalog as an attribute. |
placeholder | placeholder | string | 'Pick a date' / 'Pick a range' | Kebab-case attribute; camelCase property. |
range | — | — | — | Recorded in the catalog as an attribute. |
required | — | — | — | Recorded in the catalog as an attribute. |
side | side | 'bottom' | 'top' | 'auto' | 'auto' | Kebab-case attribute; camelCase property. |
text | — | — | — | Recorded in the catalog as an attribute. |
value | value | Date | null | DateRange | undefined | Kebab-case attribute; camelCase property. |
week-starts-on | — | — | — | Recorded in the catalog as an attribute. |
Properties
| Property | Type | Default | Notes |
|---|---|---|---|
value | Date | null | DateRange | undefined | Property-only: assign from script; not accepted as an attribute. |
defaultValue | Date | null | DateRange | null | Property-only: assign from script; not accepted as an attribute. |
placeholder | string | 'Pick a date' / 'Pick a range' | Property-only: assign from script; not accepted as an attribute. |
align | 'start' | 'end' | 'start' | Property-only: assign from script; not accepted as an attribute. |
side | 'bottom' | 'top' | 'auto' | 'auto' | Property-only: assign from script; not accepted as an attribute. |
disabled | boolean | false | Property-only: assign from script; not accepted as an attribute. |
range | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
height | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
text | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
locale | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
weekStartsOn | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
minDate | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
maxDate | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
defaultMonth | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
isDateDisabled | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
name | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
required | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
open | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
onChange | (date: Date | null) => void | (range: DateRange) => void | undefined | Property-only: assign from script; not accepted as an attribute. |
Events
| Event | Upstream prop | Payload type | Notes |
|---|---|---|---|
detent-change | onChange | (date: Date | null) => void | Composed, bubbles; fires only for a user action. |
detent-close | onClose | (reason: CloseReason) => void | Composed, bubbles; fires only for a user action. |
Slots
| Slot | Notes |
|---|---|
default | Consumer content; rendered through a slot, never re-created. |
CSS customisation
- `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
- React callback props become typed composed CustomEvents; programmatic state assignment emits none.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- `lucide-react` icon components replaced with local SVG assets (ISC notice retained).
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- Controlled/uncontrolled React pair maps to initial-value attributes plus owned state and change events.
- `range` is a boolean attribute (default false) that switches the inner calendar to range mode; the pinned source expresses it through props the row does not record.
- The persistent calendar is re-anchored on open (an explicit default-month wins, else the selected month) where upstream mounted a fresh calendar per open.
- `open` is a read-only reflected state; the Framer Motion spring is a 160ms WAAPI opacity/scale entrance, cancelled on close and disconnect and absent under reduced motion.
- The popover is not top-layer (it matches upstream absolute positioning), so clipping by an ancestor with overflow:hidden is a recorded limitation.
- `side="auto"` always opens downward below 640px, and otherwise flips up only when the space below is short and the trigger sits at least `height` from the top.
- Native form participation added; the recorded `children` render function has no declarative slot equivalent.
- The inner calendar's detent-change/detent-click/input/change are stopped at the calendar element, so a document listener sees exactly one detent-change targeted at detent-date-picker.
What it does
A date field with a popover calendar for single dates and ranges. It reuses the calendar component and emits a change when a date or range is chosen.
Upstream behaviour
- Popover scales from the trigger edge with a spring and flips above when space is tight
- Single date + date range pickers share the same Calendar underneath
- Selection pill lands before the popover closes, then focus returns to the trigger
- Esc and outside-click close; controlled or uncontrolled value
- Supports all Calendar options: minDate, maxDate, isDateDisabled, weekStartsOn, locale
Differences from upstream
- `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
- React callback props become typed composed CustomEvents; programmatic state assignment emits none.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- `lucide-react` icon components replaced with local SVG assets (ISC notice retained).
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- Controlled/uncontrolled React pair maps to initial-value attributes plus owned state and change events.
- `range` is a boolean attribute (default false) that switches the inner calendar to range mode; the pinned source expresses it through props the row does not record.
- The persistent calendar is re-anchored on open (an explicit default-month wins, else the selected month) where upstream mounted a fresh calendar per open.
- `open` is a read-only reflected state; the Framer Motion spring is a 160ms WAAPI opacity/scale entrance, cancelled on close and disconnect and absent under reduced motion.
- The popover is not top-layer (it matches upstream absolute positioning), so clipping by an ancestor with overflow:hidden is a recorded limitation.
- `side="auto"` always opens downward below 640px, and otherwise flips up only when the space below is short and the trigger sits at least `height` from the top.
- Native form participation added; the recorded `children` render function has no declarative slot equivalent.
- The inner calendar's detent-change/detent-click/input/change are stopped at the calendar element, so a document listener sees exactly one detent-change targeted at detent-date-picker.