Generative UI Date and Time Controls#
Overview#
DatePicker is a first-class vocabulary control in @assistant-ui/react-generative-ui, registered alongside Select, Input, Checkbox, Slider, RadioGroup, and CheckboxGroup in the interactive vocabulary. DateTimeInput is an A2UI input type that is converted into the vocabulary rather than being a vocabulary node itself. Both participate in the same dual-mode binding/dispatch architecture that governs all interactive controls in the package.
DatePicker#
Source: DatePickerRender (render function) and vocabulary registration in packages/react-generative-ui/src/vocabulary/interactive.tsx.
Renders as a native <input type="date"> . Accepted props:
| Prop | Type | Notes |
|---|---|---|
value | string | ISO date string YYYY-MM-DD; used as initial/controlled value |
min / max | string | ISO date bounds |
label | string | Accessible label |
name | string | Field name when used inside a Form/Card |
$action | Action | Side-effect to dispatch on selection |
Binding vs. unbound behavior: When a binding is present (isBound = true), the control switches from defaultValue to a controlled value prop driven by answeredValue . On change, it calls updateBinding?.(value) and fires the $action event — both always happen together.
DateTimeInput (A2UI mapping)#
DateTimeInput is an A2UI component type that is converted into the vocabulary, not a first-class vocabulary node itself. The mapping strategy added in PR #8566 is:
- Date-only values → rendered as
DatePicker(the existing<input type="date">) - Time-bearing / ISO-offset values → rendered as a text
Inputholding the ISO string
The text-input fallback was a deliberate choice: datetime-local and time HTML inputs strip timezone offsets, which would corrupt offset-bearing timestamps.
Binding and Dispatch Architecture#
All interactive controls share the same two-layer model:
1. Live Binding (useA2uiBinding)#
useA2uiBinding(name) returns an updater function when the control is rendered under an A2uiBindingContext. Calling the updater writes the new value to the local model state at the matching JSON-pointer path in A2uiPresentRenderer . This makes the bound value available to other controls that read from the same path, but does not emit any upstream model-update operation.
2. Action Dispatch (fire)#
fire($action, $dispatch, value, element) in dispatch.ts:
- Is a no-op if either
$actionor$dispatchis absent. - Resolves
{ "$field": name }references from the nearest Form/Card context. - Merges the runtime value under
$input. - Calls the registered action handler via
$dispatch.
actionAttr serializes the Action object for placement in data-aui-action .
When a standalone control dispatches vs. only updates a binding#
The rule is: both always happen, but each may be a no-op. On every change event, a control calls:
updateBinding?.(value) // no-op if no binding context
fire($action, $dispatch, value, element) // no-op if $action or $dispatch is missing
- A control inside a Form/Card typically has a
nameand no$action; it updates the binding on change and the Form's submit button fires the action with all field values collected. - A standalone control typically has a
$action; it fires the action immediately on change and optionally updates a binding if one is wired up.
This design means there is no special "standalone mode" code path — the same onChange handler covers both cases, and the presence or absence of $action/binding context determines observable behavior.
Key Source Files#
| File | Purpose |
|---|---|
vocabulary/interactive.tsx | All interactive controls including DatePickerRender |
vocabulary/dispatch.ts | fire and actionAttr utilities |
a2ui/BindingContext.ts | useA2uiBinding hook and context |
a2ui/convert.ts | A2UI-to-vocabulary conversion, DateTimeInput mapping |
| PR #8421 | feat: bind A2UI inputs to action context |
| PR #8566 | fix: map A2UI input variants the vocabulary lacked (DateTimeInput → DatePicker or text Input) |