component — conform
Conform Date Field
The quebi DateField wired to Conform. Binds a date field's name, required, default, and validity from field metadata and renders inline errors. Every DateField display prop passes through, shouldForceLeadingZeros (two-digit day and month) included; the wire value is an ISO string either way.
- form
- conform
- date
- date-field
- validation
- leading-zeros
01 example
Bound to a Conform form
Submit with a past or empty date to see the validation error wired from field metadata.
source
conform-date-field.tsxCopy this into your project. Resolve its dependencies from the registryDependencies in the component's API entry.
"use client"
import type { FieldMetadata } from "@conform-to/react"
import { type CalendarDate, parseDate } from "@internationalized/date"
import { composeRenderProps } from "react-aria-components"
import type { DateFieldProps, DateValue } from "react-aria-components"
import { cn } from "@/lib/utils"
import { DateField, DateInput } from "@/components/date-field"
import { Description, FieldError, fieldStyles, Label } from "@/components/field"
export interface ConformDateFieldProps
extends Omit<
DateFieldProps<DateValue>,
"name" | "form" | "value" | "defaultValue" | "isRequired" | "isInvalid"
> {
/**
* A date field: the wire value is an ISO `YYYY-MM-DD` string that Conform
* coerces to a Date, so the metadata carries `Date | string`.
*/
field: FieldMetadata<Date | string>
label?: string
description?: string
}
/** Parse a Conform field's string default (ISO `YYYY-MM-DD`) into a CalendarDate.
* Returns undefined for empty/invalid values so the field starts blank. */
function toDefaultValue(value: unknown): CalendarDate | undefined {
if (typeof value !== "string" || value === "") return undefined
try {
return parseDate(value)
} catch {
return undefined
}
}
/**
* ConformDateField — DateField wired to Conform.
*
* Binds a date Conform field to the quebi segmented DateField: derives name,
* id, form, required, default, and validity from the field metadata and renders
* inline errors. The control submits an ISO `YYYY-MM-DD` string via the hidden
* input react-aria renders for it.
*
* Every `DateField` prop the field metadata does not own passes straight
* through — `granularity`, `minValue` / `maxValue`, and
* `shouldForceLeadingZeros`, which pads the day and month to two digits
* (`30.06.2026` rather than the `30.6.2026` `de-DE` asks for). The wire value
* is the ISO string either way; padding is display only.
*/
export function ConformDateField({
field,
label,
description,
className,
...props
}: ConformDateFieldProps) {
const hasErrors = !field.valid && !!field.errors
const isRequired = field.required ?? false
return (
<DateField
{...props}
id={field.id}
name={field.name}
form={field.formId}
defaultValue={toDefaultValue(field.initialValue)}
isRequired={isRequired}
isInvalid={hasErrors}
className={composeRenderProps(className, (resolved) => cn(fieldStyles, resolved))}
>
{label && (
<Label className={cn(hasErrors && "text-quebi-danger")}>
{label}
{isRequired && <span className="ml-1 text-quebi-fg">*</span>}
</Label>
)}
<DateInput />
{/* No ids and no aria-describedby here: this is a react-aria field, so it
generates the description and error ids and already points the control
at them. Setting id={field.errorId} would not break that — on mount
react-aria re-points the control at whatever id the element actually
carries — it would just duplicate wiring that is already correct.
Outside a react-aria field the ids are yours: see ConformSwitch. */}
{description && <Description>{description}</Description>}
{hasErrors && <FieldError>{field.errors?.join(", ")}</FieldError>}
</DateField>
)
}