Date segments

The model of a segmented date input: day, month and year fields with their literals.

Reach for them to build a date field with separate parts. The helpers are pure: no DOM at import time or in the call path, so they run on the server and in tests. Each result below is computed when the page is built, by running the call shown.

Import

import {
	buildDateSegments,
	segmentsToDate,
	draftStatus,
	allSegmentsEmpty,
	applyDigitToSegment,
	applyBackspaceToSegment,
	incrementSegmentValue,
	clearSegmentValue,
	setSegmentNumeric,
	focusPartAfter,
	firstEmptyOrFirstPart,
	getEditablePartTypes,
	getSegmentBounds,
	segmentAriaName,
	segmentDisplayText,
	segmentNumericValue,
	getEditableSegmentIndices,
	maxSegmentLength,
	clampSegmentValue,
	incrementSegment,
} from '@ecopages/radiant-ui/helpers';

Building and reading

buildDateSegments returns the segments, literals included, in the locale's order. Editing functions return a new array and never change the one passed in.

CallResult
buildDateSegments(null, 'en-US').map((segment) => segment.placeholder)["mm","/","dd","/","yyyy"]
buildDateSegments(new Date(2026, 10, 14), 'en-US').map((segment) => segment.value)["11","/","14","/","2026"]
segmentsToDate(buildDateSegments(new Date(2026, 10, 14), 'en-US'))Date(2026-11-14)
draftStatus(buildDateSegments(null, 'en-US')){"kind":"empty"}
draftStatus(buildDateSegments(new Date(2026, 10, 14), 'en-US')){"kind":"date","iso":"2026-11-14"}

Editing

Typed digits, Backspace and arrow-key steps, following the React Aria useDateSegment entry rules. focusNext says the segment is complete.

CallResult
applyDigitToSegment(buildDateSegments(null, 'en-US'), 'month', '1', '').focusNextfalse
applyDigitToSegment(buildDateSegments(null, 'en-US'), 'month', '5', '').focusNexttrue
incrementSegmentValue(buildDateSegments(new Date(2026, 10, 14), 'en-US'), 'month', 1).map((segment) => segment.value)["12","/","14","/","2026"]
getEditablePartTypes(buildDateSegments(null, 'en-US'))["month","day","year"]