Skip to content

No.353 · Forms· New

Phrase Date

A date field you write in words: “next fri”, “in 2 weeks”, “12 mar”. A line reads back what it understood, in full, before you commit, and a month grid agrees with the text in both directions.

The prompt

Copy this text

Automatic copying is unavailable. Copy the selected text using your device’s copy command.

Written for the variant you picked above: Paper

Build a date input that is faster to type than to click, and that never leaves you guessing how it was understood. The field: a mono caps label, then a borderless input in a 22px display serif over a 1px rule that darkens on focus, with a 44px calendar button at its end. Under it, a status line reads the input back: empty, "Write it the way you'd say it."; understood, "Reads as Friday 16 October" with the date in ink (and the year added when it is not this year or is more than 150 days away); a day before the minimum, "That day has passed."; unreadable (after blur or Enter), "I can't read that yet. Try “next fri” or “12 mar”." in the danger colour with aria-invalid. The reader is a pure function of (text, today). It accepts: today, tomorrow; a weekday or its three-letter form ("fri" is the next one, today included; "next fri" is that day in the week after this one, with weeks running Monday to Sunday); "in 3 days", "in 2 weeks", "a month" (clamping, so 31 Jan plus a month is 28 Feb); "12 mar", "12th of march", "mar 12", "12 march 2027" (without a year, the next time it comes round); "16/10", "16/10/2026" (day first); ISO dates. It validates real dates, so 31 feb is null, not 3 March. Committing: Enter, or leaving the field, replaces the text with a canonical "Fri 16 Oct 2026" and calls onChange. Escape restores the committed text. The grid: the calendar button (or ArrowDown in the field) folds open a panel below (grid-template-rows 0fr to 1fr, 280ms), not a floating popover, so nothing is clipped or portalled. It always shows six rows of seven so it never changes height. It follows the text: whatever you type that parses moves the grid to that month and rings that day (1.5px accent); the committed day is filled with ink; today has a dot; days before min are struck through and aria-disabled. role=grid with roving tabindex, arrows ±1 and ±7, PageUp and PageDown by month (Shift for a year), Home and End for the week, Enter or Space to pick, Escape to close and return focus to the field. Paper and Night themes. Selected variant — Paper (paper): Palette for this theme (Paper): --pd-accent #2f6bff; --pd-danger #b42318; --pd-ink #1b1a17; --pd-line rgb(27 26 23 / 0.16); --pd-muted #6b6861; --pd-surface #ffffff; --pd-wash rgb(27 26 23 / 0.05). Treat these as the root colour tokens, one value per role, and name them to suit your code. Select it with the theme option set to "paper". Keep every dimension, spacing value, state and motion from the brief unchanged, and keep text at 4.5:1 contrast or better on these surfaces. This selection takes precedence over references to other themes or options in the general brief. Implement this selected appearance; do not add a variant picker or alternative appearances unless requested. Implementation requirements: Use React and TypeScript. Keep the component self-contained, with uniquely scoped CSS and no animation libraries. Include required imports, styles and font setup in the result. Interaction: Type a date in words and watch the line read it back; press Enter to commit. Open the grid with the button or ArrowDown and move with the arrow keys. Motion: Grid folds open in 280ms; the reading and the month fade in over 200ms. Accessibility: A labelled input described by the reading line, which is a status region; invalid input sets aria-invalid. The month grid is a role=grid with roving tabindex, full arrow, Page and Home/End support, dated accessible names for every day, and aria-disabled for blocked days. Escape closes it and returns focus. Reduced motion removes the fold and fades. Responsive behavior: Fills its container up to 22rem; the grid cells keep a 36px minimum. Touch: Typing works on any keyboard; the calendar button opens the grid for tapping, with 36px cells and a 44px toggle. Preserve keyboard access, visible focus and reduced-motion behavior. Keep fictional demo data and simulated service calls in a separate usage example; expose callbacks for real actions and recover from rejected requests. Keep usage-example links inside the demo: use local buttons or prevent navigation. Demonstration links must not navigate to Vitrine routes or open other pages; preserve real URL support in the reusable component itself. Verify the result at narrow and wide viewport sizes, with keyboard input and reduced motion enabled.

Notes

Interaction
Type a date in words and watch the line read it back; press Enter to commit. Open the grid with the button or ArrowDown and move with the arrow keys.
Motion
Grid folds open in 280ms; the reading and the month fade in over 200ms.
Accessibility
A labelled input described by the reading line, which is a status region; invalid input sets aria-invalid. The month grid is a role=grid with roving tabindex, full arrow, Page and Home/End support, dated accessible names for every day, and aria-disabled for blocked days. Escape closes it and returns focus. Reduced motion removes the fold and fades.
Responsive
Fills its container up to 22rem; the grid cells keep a 36px minimum.
On touch
Typing works on any keyboard; the calendar button opens the grid for tapping, with 36px cells and a 44px toggle.

Featured

425 components