Date input
Native type="date" field backed by a pluggable DateAdapter so serialize/deserialize stay library-agnostic. App state is Date | null (empty ⇒ null).
Usage
import { useState } from "react";
import { DateInput } from "@sometic/react/input";
import { createNativeDateAdapter } from "@sometic/date-native";
const adapter = createNativeDateAdapter();
export function Example() {
const [value, setValue] = useState(null);
return <DateInput adapter={adapter} value={value} onValueChange={setValue} />;
}import { useState } from "react";
import { DateInput } from "@sometic/react/input";
import { createNativeDateAdapter } from "@sometic/date-native";
const adapter = createNativeDateAdapter();
export function Example(): JSX.Element {
const [value, setValue] = useState(null);
return <DateInput adapter={adapter} value={value} onValueChange={setValue} />;
}<script type="module">
import { registerInputElements } from "@sometic/elements/input";
registerInputElements();
</script>
<!-- Defaults to createNativeDateAdapter(); override via element.adapter -->
<sometic-date-input></sometic-date-input>Vue
<script setup>
import { ref } from "vue";
import { DateInput } from "@sometic/vue/input";
import { createNativeDateAdapter } from "@sometic/date-native";
const adapter = createNativeDateAdapter();
const value = ref(null);
</script>
<template>
<DateInput v-model="value" :adapter="adapter" />
</template>React and Vue require
adapter: DateAdapter(for examplecreateNativeDateAdapter()from@sometic/date-native). The custom element defaults to a native adapter internally and exposes anadapterproperty setter for swaps.
How it works
- Engine (
@sometic/dom/input-date):resolveDateInputserializes a validDatethrough the adapter into the native input string (type: "date").createDateInputControllerowns controllableDate | nullandsetFromNativeValue(empty ⇒null; invalid deserialize ⇒null). - Adapters: React/Vue require
adapter; value APIs useDate | null. On change they deserialize with the adapter and emit only whenparsed.valid(elsenull). - Custom element:
sometic-date-inputobservesvalue,disabled,readonly,invalid,shadow, defaults#adaptertocreateNativeDateAdapter(), rebuilds the controller whenvalueoradapterchanges, and dispatchesvalue-changewith{ value: Date | null }.
Date libraries stay optional peers; the core never imports dayjs/date-fns.
Anatomy
| Part | Role |
|---|---|
| Native input | Browser date control; domain value is Date |
State attributes follow Input. Invalid dates from the adapter become empty display / null value.
Props / attributes
React DateInputProps
Omit<InputProps, "type" | "value" | "defaultValue" | "onValueChange"> plus:
| Prop | Type | Default | Description |
|---|---|---|---|
adapter | DateAdapter | required | Serialize/deserialize |
value | Date | null | , | Controlled |
defaultValue | Date | null | , | Uncontrolled initial |
onValueChange | (value: Date | null) => void | , | Change |
disabled / readonly / invalid | boolean | , | State + ARIA |
name | string | , | Form association |
| styling props | from Input | , | unstyled, classes, … |
| Native attrs | remaining input HTML attrs | , | Forwarded; ref supported |
Vue
Required adapter, modelValue: Date | null, disabled, readonly. Emits update:modelValue.
Custom element (sometic-date-input)
Observed: value, disabled, readonly, invalid, shadow. Property: adapter getter/setter. Event: value-change → { value: Date | null }.
Events / callbacks
| Surface | Event | Payload |
|---|---|---|
| React | onValueChange | Date | null |
| Vue | update:modelValue | Date | null |
| Custom element | value-change | { value } |
Ignored while disabled or readonly. Empty native string ⇒ null. Invalid adapter deserialize ⇒ null.
Controlled vs uncontrolled
Same as other domain inputs: controlled value + handler, or defaultValue / CE attribute. Empty always means null, never a sentinel Invalid Date in the public callback path.
Form participation
Serialize with your adapter on submit (ISO date string, etc.). Native yyyy-mm-dd may appear in FormData depending on wiring; prefer Sometic Date | null values inside Form. Constraint attrs (min / max strings) can still be forwarded where Input allows; validate with Form validators for cross-field rules.
Accessibility
- Label clearly via Field.
- Keyboard and picker UI vary by browser/OS; provide short helper text when users may lack a graphical picker.
- Set
invalid+ error text for out-of-range or required empty values. - This is a native date field, not a custom calendar grid (no arrow-key grid contract beyond the browser control).
Styling
Native picker chrome is limited. Style the input host via state attrs / classes. Shadow DOM on the CE isolates host styles only; the OS picker UI stays platform-owned.
Edge cases
- Invalid strings ⇒
nullwhenadapter.deserializereports invalid. - Timezone / calendar date vs instant, adapters document semantics; read
@sometic/date-core/ native adapter docs before assuming UTC midnight. - Adapter swap mid-life, CE rebuilds controller; React/Vue should keep a stable adapter instance per field when possible.
- SSR, adapters must not touch browser globals at import time; register CE in the browser.
- No DatePicker popover in this beta surface; do not invent overlay APIs here.
Performance notes
Adapters are optional peer packages so date-fns/dayjs are not forced into every bundle. Prefer one adapter instance shared across fields that share the same library.
When to use / When not
Use when you need Date | null values with a swappable serialize strategy on a native date control.
Do not use for:
- Free-text date entry without a native control (compose Input + validation).
- Full calendar popovers / ranges (not shipped in this beta).
- Date-time with time-of-day unless your adapter and
typemapping explicitly support it (this resolve usestype: "date").
FAQ
Why adapters? Date libraries stay optional. The engine only depends on the DateAdapter contract from @sometic/date-core.
Which adapter by default? @sometic/date-native for the CE. React/Vue require an explicit adapter prop.
Is there a DatePicker UI? Not in this beta. Use DateInput for native date fields.
Empty value? Always null in callbacks when cleared or invalid.
How do min/max work? Forward constraint attrs / validate in Form. Do not assume every adapter interprets min/max the same way.
Can I set element.adapter on the CE? Yes; the setter rebuilds the controller.
Does React forward refs? Yes, to the underlying <input type="date">.
Vue v-model type? Date | null.
SSR safe? Resolvers are import-safe; register custom elements only in the browser.
Bundle tip? Import @sometic/react/input plus only the date adapter package you need.