Interactive demo of date picker field
/**
* Date Field Demo - Interactive examples of date picker fields
*/
import { Form, FormBuilder } from '@saastro/forms';
import { FormProvider } from '@/components/FormProvider';
import { TooltipProvider } from '@/components/ui/tooltip';
const config = FormBuilder.create('date-demo')
.layout('manual')
.columns(12)
.addField('birthdate', (f) =>
f
.type('date')
.label('Date of Birth')
.placeholder('Select your birth date')
.helperText('When were you born?')
.required('Date of birth is required')
.columns({ default: 12, md: 6 }),
)
.addField('appointment', (f) =>
f
.type('date')
.label('Appointment Date')
.placeholder('Select appointment date')
.helperText('Choose a date for your appointment')
.required()
.columns({ default: 12, md: 6 }),
)
.addField('deadline', (f) =>
f
.type('date')
.label('Project Deadline')
.placeholder('Select deadline')
.helperText('When should this be completed?')
.optional()
.columns({ default: 12 }),
)
.addStep('main', ['birthdate', 'appointment', 'deadline'])
.build();
export default function DateDemo() {
const handleSubmit = (data: Record<string, unknown>) => {
console.log('Form submitted:', data);
alert('Form submitted! Check console for data.');
};
return (
<TooltipProvider>
<FormProvider>
<Form config={config} onSubmit={handleSubmit} className="space-y-4" />
</FormProvider>
</TooltipProvider>
);
} Overview
The date picker field provides a calendar interface for selecting a single date, built on react-day-picker. It renders either a popover-triggered calendar (the default) or an inline calendar, controlled by the dateType prop, and supports date constraints through Zod schemas.
Usage
Basic Date Picker
import { FormBuilder } from '@saastro/forms';
const config = FormBuilder.create('form')
.addField('birthdate', (f) =>
f
.type('date')
.label('Date of Birth')
.placeholder('Select your birth date')
.required('Date of birth is required'),
)
.addStep('main', ['birthdate'])
.build();
Display Modes (dateType)
The dateType prop switches between two render modes:
'popover'(default) — an outline button that opens the calendar in a popover. The button shows the selected date (or the placeholder) and the calendar uses dropdown month/year navigation. The popover closes when a date is picked.'simple'— the calendar is rendered inline, always visible, with no trigger button.
// Inline calendar instead of the default popover
.addField('checkIn', (f) =>
f.type('date')
.label('Check-in Date')
.dateType('simple')
.required()
)
With Date Constraints
.addField('appointment', (f) =>
f.type('date')
.label('Appointment Date')
.placeholder('Select a date')
// Future dates only (via Zod) — z.date() already rejects empty values,
// so the field is implicitly required
.schema(z.date().min(new Date(), 'Must be a future date'))
)
Don’t mix
.schema(zodSchema)with declarative validation methods like.required()or.regex()on the same field — calling a declarative method replaces a previously set Zod schema, silently dropping its constraints. Use one approach or the other.
Default Value
.addField('startDate', (f) =>
f.type('date')
.label('Start Date')
.value(new Date())
.required()
)
JSON Configuration
{
"type": "date",
"label": "Date of Birth",
"placeholder": "Select your birth date",
"dateType": "popover",
"schema": { "required": true }
}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
type | 'date' | - | Field type (required) |
dateType | 'simple' | 'popover' | 'popover' | Inline calendar (simple) or popover button |
label | string | - | Label text |
placeholder | string | 'Pick a date' | Popover button text when no date is selected |
helperText | string | - | Help text below field |
value | Date | - | Default date |
columns | Partial<Record<Breakpoint, number>> | - | Grid columns by breakpoint |
disabled | boolean | function | ConditionGroup | false | Disable the field |
hidden | boolean | function | ConditionGroup | Responsive | false | Hide the field |
Declared but not yet implemented:
showTime?: booleanandpresets?: Array<{ label: string; value: number }>exist on the field’s type (and have builder methods.showTime()/.datePresets()), but the renderer currently ignores them — setting them has no effect.
Display Format & Localization
In popover mode, the selected date is shown using the date-fns 'PPP' format — English by default (e.g. June 11th, 2026). The default placeholder is 'Pick a date', overridable with the placeholder prop or per-locale via the i18n overlay. The date display locale is configurable globally with setDateLocale:
import { setDateLocale } from '@saastro/forms';
import { es } from 'date-fns/locale';
setDateLocale(es); // 'PPP' now renders "11 de junio de 2026"
Validation
Required Date
.addField('eventDate', (f) =>
f.type('date')
.label('Event Date')
.required('Please select a date')
)
With Zod Constraints
import { z } from 'zod';
const oneYearFromNow = new Date();
oneYearFromNow.setFullYear(oneYearFromNow.getFullYear() + 1);
.addField('deadline', (f) =>
f.type('date')
.label('Deadline')
.schema(z.date()
.min(new Date(), 'Must be a future date')
.max(oneYearFromNow, 'Must be within the next year')
)
)
Styling
Custom Classes
.addField('birthdate', (f) =>
f.type('date')
.label('Date of Birth')
.required()
.classNames({
wrapper: 'bg-muted/30 p-4 rounded-lg',
input: 'border-2 border-primary/20',
label: 'text-lg font-semibold',
error: 'text-destructive text-sm',
})
)
Responsive Layout
.addField('eventDate', (f) =>
f.type('date')
.label('Event Date')
.columns({ default: 12, md: 6 })
)
JSON Styling
{
"type": "date",
"label": "Date of Birth",
"wrapper_className": "bg-muted/30 p-4 rounded-lg",
"input_className": "border-2 border-primary/20",
"label_className": "text-lg font-semibold",
"columns": { "default": 12, "md": 6 }
}
Related Fields
- Date Range - Select a range of dates
Accessibility
- Built on react-day-picker
- Full keyboard navigation
- Screen reader support
- ARIA labels for calendar navigation