Skip to content

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.

Terminal window
pnpm dlx shadcn@latest add https://sg-widgets.vercel.app/r/react/date-editor.json
Terminal window
pnpm dlx shadcn-svelte@latest add https://sg-widgets.vercel.app/r/svelte/date-editor.json
DateEditor: three sizes, set, unset, and the three marked states

React

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
proptypedefaultmeaning
valuestring | nullnullThe stored day. Two-way in Svelte.
onValueChange(value: string | null) => void—Called when the input commits or a day is picked.
fieldPick<FieldSchema, 'displayName' | 'mandatory'> | nullnullSupplies the accessible label and the required flag.
disabledbooleanfalse
readonlybooleanfalseKeeps the value readable and does not open the popover.
invalidbooleanfalseForced invalid state.
errorstring | nullnullA message from the caller, shown in place of the parse error.
onErrorChange(error: string | null) => void—Called when the parse error appears or clears.
placeholderstring'YYYY-MM-DD'Shown on the button and in the typed day while the field is unset.
openbooleanfalseWhether the calendar popover is showing. Two-way in Svelte.
class / classNamestring—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.
inlinebooleanfalseThe row form: the button takes the width of its value.
eventpayloadwhen
onOpenChangebooleanThe 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.

keydoes
EnterOn the button, opens the popover. In the typed day, commits it and closes the popover.
EscapeIn the popover, restores the stored day and closes the popover.
SpaceOpens the popover, from the button.
TabMoves from the typed day to the calendar.
arrowsMove between days, inside the calendar.
Enterfrom ValueEditorCommits the draft. In a textarea it adds a line, and commitOnEnter turns the commit off.
Escapefrom ValueEditorRestores the stored value and drops what the last parse said.
Tabfrom ValueEditorLeaves the control, which commits.

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).