Calendar Input
CalendarInputView pairs a read-only text input with a Calendar in a popover. Clicking the field opens the calendar; picking a day fills the field with the formatted date. It’s a convenience wrapper for the common “date field” pattern where the value is always chosen from the calendar rather than typed.
Installation
import { useState } from 'react';import { CalendarInputView } from '@harnessio/ui/components';
const DateField = () => { const [value, setValue] = useState<string>('');
return ( <CalendarInputView value={value} setValue={(date) => setValue(date.toISOString())} placeholder="Select a date" /> );};
export default DateField;The field stores its value as a string that you own. setValue hands you a Date when a day is picked — convert and store it however you like (an ISO string above), and pass it back in through value.
Anatomy
CalendarInputView is a single, self-contained component — you don’t compose its parts. Internally it wires together three design-system components:
<Popover.Root> <Popover.Trigger asChild> <TextInput readOnly /> {/* the field you click */} </Popover.Trigger> <Popover.Content hideArrow> <Calendar mode="single" /> {/* the picker */} </Popover.Content></Popover.Root>- Field — a read-only
TextInputthat acts as the popover trigger. It shows the selected date viatoLocaleDateString()(or theplaceholderwhen empty) and uses a pointer cursor to signal it’s clickable. - Popover — opens on click and holds the calendar; it renders without the arrow (
hideArrow). - Calendar — a single-select
Calendar. Choosing a day callssetValuewith thatDate.
The field is read-only by design — there’s no free-text entry, so every value comes from the calendar. Reach for the plain Calendar when you need range or multi-date selection, or an inline picker without the input.
Best practices
Do
- Use
CalendarInputViewfor a compact single-date field where the calendar is the only way to enter a value. - Pair it with a visible Label so the field’s purpose is clear (see the accessibility note below — it has no built-in labelling).
- Store the returned
Datein whatever format your backend expects, and feed a matching string back throughvalue.
Don’t
- Don’t use it when people need to pick a range or several dates — use Calendar directly.
- Don’t rely on it for free-typed dates; the field is read-only and can’t be typed into.
- Don’t expect to clear the field through the calendar — see the known limitations.
Content
- Write a
placeholderthat names the date being collected (“Select a start date”), not just “Select date”. - Keep the surrounding label short and specific (“Due date”, “Effective date”).
Accessibility
The field is a real TextInput and the popover/calendar bring their own semantics, so the control is focusable and the picker is operable by keyboard once open.
Keyboard
- The field is in the tab order; opening the popover surfaces the
Calendar, whose days are navigable with the arrow keys and selectable with Enter/Space (see the Calendar accessibility notes). - Because the field is
readOnly, typing does nothing — the value only changes through the calendar.
Labeling
- The selected date is rendered as the input’s value using the browser locale’s
toLocaleDateString().
Known limitations
- There’s no built-in label and no way to add one.
CalendarInputViewonly acceptsvalue,setValue, andplaceholder— it doesn’t forwardid,aria-label, orclassName, so it can’t be programmatically associated with a<label>. The placeholder is the field’s only text, and a placeholder isn’t a reliable accessible name. Until the component forwards these props, wrap it so a visible label sits adjacent, and treat the missing association as a gap to raise with the component’s owners. - The calendar can’t clear the field. Deselecting a day calls
setValue(date ?? new Date()), which falls back to today — so there’s no path back to an empty value through the UI. Resetvaluefrom your own state if you need a clear action. - The display format isn’t configurable. The value always renders via
toLocaleDateString()in the browser’s locale; there’s no prop to control the format shown in the field.
Properties
Prop | Required | Default | Type |
|---|---|---|---|
| value | false | string | |
| setValue | true | (date: Date) => void | |
| placeholder | false | 'Select date' | string |