Date builder with semantic min/max bounds. Stored as a string, validated as a date.
minDate()andmaxDate()accept aDateobject or an ISO string- Inherits string builder methods, so
pattern()andtransform()work for edge cases - The renderer adapts per platform (native date picker on mobile, input on web)
Date.web.tsxtsx
| 1 | const schema = { |
| 2 | startDate: field.date('Start date') |
| 3 | .required() |
| 4 | .minDate(new Date(), 'Choose a future date.'), |
| 5 | } |
Defaults, inheritance & field methods
- defaultValue is
'' - type is
date - Shared methods: see Base field builder
- String builder methods: see field.text()
Date-specific methods:
| Method | Type | Description |
|---|---|---|
minDate(date, message?) | Date | string | Sets a lower date bound such as "no past dates" (inclusive - same day is allowed). |
maxDate(date, message?) | Date | string | Sets an upper date bound such as "must be at least 18 years old" (inclusive). |
before(date, message?) | Date | string | FieldReference | Requires the value to be strictly before another date. Accepts a literal date or a ref() to another date field - great for startDate.before(ref('endDate')) style rules. |
after(date, message?) | Date | string | FieldReference | Requires the value to be strictly after another date. Also accepts a ref() so you can express cross-field ordering without superRefine. |
between(start, end, message?) | Date | string | number | Requires the value to fall inside [start, end] inclusively. Takes literals only (not refs) - use before() + after() for cross-field windows. |
past(message?) | message?: string | Requires the value to be in the past, evaluated at validation time. Empty values are ignored so you can still combine with required() for the presence check. |
future(message?) | message?: string | Requires the value to be in the future, evaluated at validation time. Useful for "start in the future" rules on scheduling forms. |
minAge(age, message?) | age: number | Age gate: requires the date of birth to correspond to at least age years, with month/day awareness so people born yesterday are not prematurely aged up. |
maxAge(age, message?) | age: number | Upper age cap based on date of birth, evaluated the same way as minAge(). |
Recipes
Patterns that showcase date-specific strengths.
Future-only booking
BookingDate.tsxtsx
| 1 | const schema = { |
| 2 | startDate: field.date('Start date') |
| 3 | .required() |
| 4 | .minDate(new Date(), 'Choose a future date.'), |
| 5 | } |
Age gate (18+)
AgeGate.tsxtsx
| 1 | const schema = { |
| 2 | dateOfBirth: field.date('Date of birth') |
| 3 | .maxDate('2008-01-01', 'You must be at least 18 years old.'), |
| 4 | } |
Windowed campaign
CampaignWindow.tsxtsx
| 1 | const schema = { |
| 2 | campaignEnd: field.date('Campaign end') |
| 3 | .minDate('2026-04-01') |
| 4 | .maxDate('2026-12-31'), |
| 5 | } |
Cross-field date range
DateRange.tsxtsx
| 1 | const schema = { |
| 2 | startDate: field.date('Start date').required(), |
| 3 | endDate: field.date('End date') |
| 4 | .required() |
| 5 | .validate((value, allValues) => |
| 6 | value > allValues.startDate |
| 7 | ? null |
| 8 | : 'End date must be after start date.', |
| 9 | ), |
| 10 | } |