DateEditor
Edits a date field from one button, in every context.
The button carries a calendar icon, the stored day or the placeholder, and the invalid state; the popover under it holds a typed day and the calendar, in that order.
Install
Section titled “Install”pnpm dlx shadcn@latest add https://sg-widgets.vercel.app/r/react/date-editor.jsonpnpm dlx shadcn-svelte@latest add https://sg-widgets.vercel.app/r/svelte/date-editor.jsonReact
Loading the React demo…
Svelte
Loading the Svelte demo…
| typed | emitted |
|---|---|
2026-09-02 |
"2026-09-02" |
| a day picked in the calendar | that day, as YYYY-MM-DD |
| empty | null |
2026-02-30 |
nothing; no such day |
09/02/2026, 2026-9-8, a timestamp |
nothing; wrong format |
| prop | type | default | meaning |
|---|---|---|---|
value | string | null | null | The stored day. Two-way in Svelte. |
onValueChange | (value: string | null) => void | — | Called when the input commits or a day is picked. |
field | Pick<FieldSchema, 'displayName' | 'mandatory'> | null | null | Supplies the accessible label and the required flag. |
disabled | boolean | false | |
readonly | boolean | false | Keeps the value readable and does not open the popover. |
invalid | boolean | false | Forced invalid state. |
error | string | null | null | A message from the caller, shown in place of the parse error. |
onErrorChange | (error: string | null) => void | — | Called when the parse error appears or clears. |
placeholder | string | 'YYYY-MM-DD' | Shown on the button and in the typed day while the field is unset. |
open | boolean | false | Whether the calendar popover is showing. Two-way in Svelte. |
class / className | string | — | Merged after the widget's own classes. |
errorMessagefrom ValueEditor | (message: string) => ReactNode / Snippet<[string]> | — | Renders the message. Default is a small destructive line under the control. |
size | 'sm' | 'md' | 'lg' | 'md' | Button height. |
inline | boolean | false | The row form: the button takes the width of its value. |
Events
Section titled “Events”| event | payload | when |
|---|---|---|
onOpenChange | boolean | The calendar opened or closed. |
onValueChange fires on commit and on a pick. Input that does not parse emits nothing.
onOpenChange fires when the calendar popover opens or closes. Svelte also binds it with bind:open.
errorMessage receives the message and renders it.
Keyboard
Section titled “Keyboard”| key | does |
|---|---|
Enter | On the button, opens the popover. In the typed day, commits it and closes the popover. |
Escape | In the popover, restores the stored day and closes the popover. |
Space | Opens the popover, from the button. |
Tab | Moves from the typed day to the calendar. |
| arrows | Move between days, inside the calendar. |
| Enterfrom ValueEditor | Commits the draft. In a textarea it adds a line, and commitOnEnter turns the commit off. |
| Escapefrom ValueEditor | Restores the stored value and drops what the last parse said. |
| Tabfrom ValueEditor | Leaves the control, which commits. |
API behaviour
Section titled “API behaviour”A date is exactly YYYY-MM-DD, with no time and no zone, and the API validates the day rather than
only parsing it: 2026-02-30 is refused by the same message as tomorrow. Any timestamp is a 400,
on write and as a filter value (field_types/date).
Both null and the empty string clear the field and read back as null, so there is one empty state
(field_types/date).