Skip to content
v2.5.0
English
Русский
Documentation

DateField

DateField is a compound component for single-date entry that combines typed input, optional calendar selection, and field-level constraints in one control.
date-field.tsx · 67 lines
import {
  CalendarContent,
  CalendarDay,
  CalendarDays,
  CalendarHeader,
  CalendarMonth,
  CalendarMonthLabel,
  CalendarMonths,
  CalendarNextButton,
  CalendarPrevButton,
  CalendarViewButton,
  CalendarViewButtonGroup,
Browser support
Newly available 2024
  • Chrome 125
  • Edge 125
  • Firefox 128
  • Safari 18
  • Safari on iOS 18
Bundle size
Tested in
38 tests

Summary

DateField is a compound component for single-date entry that combines typed input, optional calendar selection, and field-level constraints in one control. It is the field-first date-input layer, with the calendar acting as an optional picking aid rather than the primary abstraction.

Imports

import {
  DateField,
  DateFieldInput,
  DateFieldCalendar,
  DateFieldTriggerIconButton,
  type DateFieldProps,
} from '@vega-ui/react';

Exported Types

  • DateFieldProps
  • DateFieldInputProps
  • DateFieldCalendarProps
  • DateFieldTriggerIconButtonProps

Minimal Composition

minimal-composition.tsx · 67 lines
import {
  CalendarContent,
  CalendarDay,
  CalendarDays,
  CalendarHeader,
  CalendarMonth,
  CalendarMonthLabel,
  CalendarMonths,
  CalendarNextButton,
  CalendarPrevButton,
  CalendarViewButton,
  CalendarViewButtonGroup,

Required Parts

  • DateField: root state and formatting owner
  • DateFieldInput: typed date entry surface

Optional Parts

  • DateFieldTriggerIconButton: calendar trigger affordance
  • DateFieldCalendar: visual picker content, usually mounted in Popover

Composition Order

  1. DateField
  2. DateFieldInput
  3. Popover
  4. DateFieldTriggerIconButton
  5. DateFieldCalendar

Variants

  • Input-only versus input-plus-calendar composition
  • Trigger-driven picker versus typed entry only
  • Constrained state through min, max, and disabledDates

Edge Cases

  • Locale, timezone, and serialization rules still belong to the consumer.
  • Partial typed values are common during editing and should not be treated as final values.
  • Overlay behavior should be tested inside dialogs, drawers, and scroll containers.
  • The same business rule should drive typed validation and calendar blocking; they should not drift into two different policies.

Common Mistakes

  • Passing Date objects or display-format strings to min / max instead of ISO YYYY-MM-DD strings.
  • Assuming the field solves timezone policy by itself.
  • Leaving the trigger icon button unlabeled in accessible flows.
  • Treating min, max, and disabledDates as visual hints instead of validation rules.

Examples

Basic

Basic: typed date with a calendar popover

A labelled field where users type a date or pick it in a popover calendar. defaultValue on the root is an ISO YYYY-MM-DD day; the input shows it in format, and the helper text tells users which format to type.

en-US
ru-RU
ar-EG
he-IL
typed-date-with-a-calendar-popover.tsx · 75 lines
import {
  CalendarContent,
  CalendarDay,
  CalendarDays,
  CalendarHeader,
  CalendarMonth,
  CalendarMonthLabel,
  CalendarMonths,
  CalendarNextButton,
  CalendarPrevButton,
  CalendarViewButton,
  CalendarViewButtonGroup,

Controlled/Stateful

Controlled/Stateful: preset dates

value and onChangeValue on the root keep the ISO day in parent state. Buttons set it from outside and the input shows it in format; while the typed text is incomplete the value is ''.

preset-dates.tsx · 101 lines
import { useState } from 'react';
import {
  Button,
  CalendarContent,
  CalendarDay,
  CalendarDays,
  CalendarHeader,
  CalendarMonth,
  CalendarMonthLabel,
  CalendarMonths,
  CalendarNextButton,
  CalendarPrevButton,

Controlled/Stateful: check-out starts after check-in

The check-in day drives the min of the check-out field. When check-in moves past an already typed check-out, the check-out is clamped to the new min and onChangeValue reports the clamped day, so the night count stays correct.

check-out-starts-after-check-in.tsx · 137 lines
import { useState } from 'react';
import {
  CalendarContent,
  CalendarDay,
  CalendarDays,
  CalendarHeader,
  CalendarMonth,
  CalendarMonthLabel,
  CalendarMonths,
  CalendarNextButton,
  CalendarPrevButton,
  CalendarViewButton,

Form/Integration

Form/Integration: submitting an ISO date

DateFieldInput is a native <input>: with a name it would submit the typed text, for example 15.01.2026. Here onChangeValue mirrors the ISO day into a hidden input, so FormData gets 2026-01-15. required and pattern block an empty or incomplete date, and the reset button restores defaultValue.

submitting-an-iso-date.tsx · 95 lines
import { FormEvent, useState } from 'react';
import {
  Button,
  CalendarContent,
  CalendarDay,
  CalendarDays,
  CalendarHeader,
  CalendarMonth,
  CalendarMonthLabel,
  CalendarMonths,
  CalendarNextButton,
  CalendarPrevButton,

Layout/Overlay

Layout/Overlay: date field inside a dialog

The calendar popover opens above the dialog that contains the field. The form uses method='dialog', so a valid submit closes the dialog.

date-field-inside-a-dialog.tsx · 106 lines
import { CSSProperties } from 'react';
import { XIcon } from '@vega-ui/icons';
import {
  Button,
  CalendarContent,
  CalendarDay,
  CalendarDays,
  CalendarHeader,
  CalendarMonth,
  CalendarMonthLabel,
  CalendarMonths,
  CalendarNextButton,

Layout/Overlay: close the calendar after a pick

The popover stays open after a pick by default, so users can correct it. To close it on pick, control open on the Popover and close it from onChangeValue of DateFieldCalendar; navigating months does not call it.

close-calendar-after-pick.tsx · 74 lines
import { useState } from 'react';
import {
  CalendarContent,
  CalendarDay,
  CalendarDays,
  CalendarHeader,
  CalendarMonth,
  CalendarMonthLabel,
  CalendarMonths,
  CalendarNextButton,
  CalendarPrevButton,
  CalendarViewButton,

Error

Error: required and incomplete dates

required and pattern are native constraints of the input: submit fires invalid while the field is empty or the date is incomplete. The handler picks the message from validity, error on the root and aria-invalid mark the field, and typing clears the error. The mask clamps every complete date to a real day, so checking completeness is enough.

required-and-incomplete-dates.tsx · 104 lines
import { FormEvent, useState } from 'react';
import {
  Button,
  CalendarContent,
  CalendarDay,
  CalendarDays,
  CalendarHeader,
  CalendarMonth,
  CalendarMonthLabel,
  CalendarMonths,
  CalendarNextButton,
  CalendarPrevButton,

Disabled

Disabled: locked contract date

disabled on the root disables the input and the calendar trigger. The helper text explains why the date cannot be changed.

locked-contract-date.tsx · 73 lines
import {
  CalendarContent,
  CalendarDay,
  CalendarDays,
  CalendarHeader,
  CalendarMonth,
  CalendarMonthLabel,
  CalendarMonths,
  CalendarNextButton,
  CalendarPrevButton,
  CalendarViewButton,
  CalendarViewButtonGroup,

Disabled: disabled by a fieldset

A native <fieldset disabled> disables the input and the trigger button inside it, so the calendar cannot open either. The checkbox toggles the whole group without passing disabled to the field.

disabled-by-fieldset.tsx · 94 lines
import { useState } from 'react';
import {
  CalendarContent,
  CalendarDay,
  CalendarDays,
  CalendarHeader,
  CalendarMonth,
  CalendarMonthLabel,
  CalendarMonths,
  CalendarNextButton,
  CalendarPrevButton,
  CalendarViewButton,

Disabled: read-only date

readOnly on DateFieldInput keeps the value focusable, selectable and submitted with the form. The field has no readOnly of its own and DateFieldCalendar writes into the input even when it is read-only, so leave the calendar trigger out.

read-only-date.tsx · 13 lines
import { DateField, DateFieldInput, HelperText, Label } from '@vega-ui/react';

export default function ReadOnlyDate() {
  return (
    <div style={{ display: 'grid', gap: 'var(--spacing-3)', width: '100%', maxWidth: 280 }}>
      <Label htmlFor='account-created'>Account created</Label>
      <DateField format='dd.MM.yyyy' separator='.' defaultValue='2024-09-02'>
        <DateFieldInput id='account-created' name='accountCreated' readOnly aria-describedby='account-created-hint' />
      </DateField>
      <HelperText id='account-created-hint'>Set by the system. The value is still submitted with the form.</HelperText>
    </div>
  );

Edge

Edge: typed dates are clamped

A typed day past the end of the month is clamped to the month length, so 31.02.2026 becomes 28.02.2026. A complete date outside min and max is replaced by the nearest bound, so 05.01.2026 becomes 10.01.2026. The calendar disables the same days.

typed-dates-are-clamped.tsx · 89 lines
import { useState } from 'react';
import {
  CalendarContent,
  CalendarDay,
  CalendarDays,
  CalendarHeader,
  CalendarMonth,
  CalendarMonthLabel,
  CalendarMonths,
  CalendarNextButton,
  CalendarPrevButton,
  CalendarViewButton,

Edge: weekends unavailable

disabledDates takes ISO days or a function. It applies only to the calendar: a typed weekend is accepted, so the submit handler checks the same isWeekend rule and shows an error.

weekends-unavailable.tsx · 116 lines
import { FormEvent, useState } from 'react';
import {
  Button,
  CalendarContent,
  CalendarDay,
  CalendarDays,
  CalendarHeader,
  CalendarMonth,
  CalendarMonthLabel,
  CalendarMonths,
  CalendarNextButton,
  CalendarPrevButton,

Edge: calendar popup in another locale

locale sets month and weekday names and the first day of the week in the calendar. The typed format still comes from format, and the labels of the trigger and month buttons are yours to translate.

calendar-popup-in-another-locale.tsx · 73 lines
import {
  CalendarContent,
  CalendarDay,
  CalendarDays,
  CalendarHeader,
  CalendarMonth,
  CalendarMonthLabel,
  CalendarMonths,
  CalendarNextButton,
  CalendarPrevButton,
  CalendarViewButton,
  CalendarViewButtonGroup,

Anatomy

Overview

DateField is a compound component that coordinates typed date entry, optional calendar selection, and shared field state under one root.

Required Parts

DateField

Required. Owns date parsing, formatting, disabled-date rules, and shared field state.

DateFieldInput

Required. Provides the typed date input surface.

Optional Parts

DateFieldTriggerIconButton

Optional trigger affordance for opening a calendar overlay.

DateFieldCalendar

Optional visual date picker that should usually be mounted inside Popover.

Its children are the Calendar parts: CalendarHeader with CalendarPrevButton, CalendarViewButtonGroup (CalendarViewButton view='month' and view='year'), and CalendarNextButton, then CalendarContent with CalendarDays, CalendarMonths, and CalendarYears. The calendar takes locale and calendar from DateField.

Composition Order

  1. DateField
  2. DateFieldInput
  3. Popover
  4. DateFieldTriggerIconButton
  5. DateFieldCalendar
  6. CalendarHeader and CalendarContent with the calendar views

Valid Composition Patterns

minimal-composition.tsx · 67 lines
import {
  CalendarContent,
  CalendarDay,
  CalendarDays,
  CalendarHeader,
  CalendarMonth,
  CalendarMonthLabel,
  CalendarMonths,
  CalendarNextButton,
  CalendarPrevButton,
  CalendarViewButton,
  CalendarViewButtonGroup,

Invalid Composition Patterns

DateFieldInput outside DateField

This breaks shared formatting and value synchronization.

Calendar trigger without an actual calendar overlay

The button suggests a picker flow that does not exist.

Treating calendar constraints as presentation-only

min, max, and disabledDates should stay aligned with real validation rules.