Elements

Components / Forms

Date Input

Text fields for dates and times that open the Calendar in a dropdown. Users can type the value or pick it. Every variant separates the human-readable displayFormat from the machine-readable valueFormat it emits.

Installation

bash
npx shadcn add https://raw.githubusercontent.com/levi-putna/elements/main/registry/date-input/registry.json

Display format vs value format

Show people a friendly, unambiguous date while storing a machine-friendly one. The field renders displayFormat; onValueChange emits valueFormat. Pick a date below and watch both update.

Display vs value
display "EEEE, do MMMM yyyy"—
value "dd/MM/yyyy"—
tsx
{/* The field shows displayFormat; onValueChange emits valueFormat. */}
<DateInput
  displayFormat="EEEE, do MMMM yyyy"   // "Tuesday, 16th June 2026"
  valueFormat="dd/MM/yyyy"             // "16/06/2026"
/>

Common format tokens

Any date-fns format pattern works. The left column is the token; the right is what it renders for 16 June 2026.

PropTypeDefaultDescription
d MMM yyyy16 Jun 2026-Compact, unambiguous — the default display format.
PPPJune 16th, 2026-Localized long date (date-fns shorthand).
EEEE, do MMMM yyyyTuesday, 16th June 2026-Full weekday and month.
dd/MM/yyyy16/06/2026-Day-first numeric (most of the world).
MM/dd/yyyy06/16/2026-Month-first numeric (US).
yyyy-MM-dd2026-06-16-ISO 8601 — the recommended value format for storage/APIs.
h:mm a9:00 AM-12-hour time with meridiem.
HH:mm09:00-24-hour time.
yyyy-MM-dd'T'HH:mm2026-06-16T09:00-ISO date-time (literals wrapped in single quotes).

DateInput

A single date. Type it (parsed against displayFormat on blur or Enter) or open the calendar. Unparseable text flags the field invalid instead of being silently dropped.

DateInput
value2026-06-16
tsx
import { DateInput } from "@/components/ui/date-input"

export function Example() {
  const [value, setValue] = React.useState("")

  return (
    <DateInput
      value={value}
      onValueChange={setValue}
      displayFormat="d MMM yyyy"   // shown in the field → "16 Jun 2026"
      valueFormat="yyyy-MM-dd"     // emitted to onValueChange → "2026-06-16"
    />
  )
}

TimeInput

A time of day. The dropdown lists options every stepminutes, and the field still accepts free typing like “2:15 PM”.

TimeInput
value09:00
tsx
import { TimeInput } from "@/components/ui/date-input"

<TimeInput
  defaultValue="09:00"
  displayFormat="h:mm a"   // "9:00 AM"
  valueFormat="HH:mm"      // "09:00"
  step={30}                // minutes between suggestions
/>

DateTimeInput

Date and time together. The calendar and a time list share one dropdown; picking a day keeps the chosen time.

DateTimeInput
value—
tsx
import { DateTimeInput } from "@/components/ui/date-input"

<DateTimeInput
  displayFormat="d MMM yyyy, h:mm a"      // "16 Jun 2026, 9:00 AM"
  valueFormat="yyyy-MM-dd'T'HH:mm"        // "2026-06-16T09:00"
/>

DateRangeInput

A start and end date. The trigger reads start – end and opens a two-month calendar in range mode. onValueChange emits { from, to }.

DateRangeInput
from—
to—
tsx
import { DateRangeInput, type DateRangeValue } from "@/components/ui/date-input"

export function Example() {
  const [range, setRange] = React.useState<DateRangeValue>({})

  return (
    <DateRangeInput
      value={range}
      onValueChange={setRange}
      displayFormat="d MMM yyyy"
      valueFormat="yyyy-MM-dd"
    />
  )
  // range → { from: "2026-06-16", to: "2026-06-20" }
}

Displaying dates

For read-only output — tables, activity feeds, audit logs — use DateBadge and DateTag. Both take the same displayFormat and an optional timeZone.

DateBadge

A compact, non-interactive badge. Optionally pin it to a time zone and show the zone label.

DateBadge
16 Jun 2026Jun 16, 2026 9:47 AMUTCJune 16, 2026 9:47:29 AMGMT+10June 16, 2026 7:47:29 PM
tsx
import { DateBadge } from "@/components/ui/date-display"

<DateBadge date="2026-06-16T09:47:29Z" displayFormat="d MMM yyyy" />

{/* Pin to a zone and show its label */}
<DateBadge
  date="2026-06-16T09:47:29Z"
  displayFormat="MMMM d, yyyy h:mm:ss a"
  timeZone="Australia/Sydney"
  showZone
/>

DateTag

An inline date with a dashed underline. Hover (or focus) it to reveal how long ago it was and the time in both the displayed zone and your local zone — so a reader in another country always knows what the timestamp means for them.

DateTag

Report generated 16 Jun 2026, 9:47 AM — hover to see it in your local time.

tsx
import { DateTag } from "@/components/ui/date-display"

{/* Displayed in UTC; hovering reveals the viewer's local zone + "x ago". */}
<DateTag
  date="2026-06-16T09:47:29Z"
  displayFormat="d MMM yyyy, h:mm a"
  detailFormat="d MMM yyyy, h:mm:ss a"
  timeZone="UTC"
/>

Props

Shared (DateInput, TimeInput, DateTimeInput)

PropTypeDefaultDescription
valuestring-Controlled value, a string in valueFormat.
defaultValuestring-Uncontrolled initial value, a string in valueFormat.
onValueChange(value: string) => void-Fires with the value formatted by valueFormat ("" when cleared).
onDateChange(date: Date | undefined) => void-Escape hatch — fires with the raw Date.
displayFormatstring-date-fns pattern shown in the field.
valueFormatstring-date-fns pattern emitted by onValueChange and the hidden form input.
namestring-Renders a hidden input with the valueFormat string for native form submission.
disabledboolean-Disables the field and trigger.

TimeInput

PropTypeDefaultDescription
stepnumber30Minutes between suggested options in the dropdown list.

DateTimeInput

PropTypeDefaultDescription
stepnumber30Minutes between suggested time options.
timeFormatstring"h:mm a"date-fns pattern for the time-list labels.
calendarPropsPartial<CalendarProps>-Forwarded to the underlying Calendar (e.g. disabled dates, captionLayout).

DateRangeInput

PropTypeDefaultDescription
value{ from?: string; to?: string }-Controlled range, strings in valueFormat.
onValueChange(value: { from?, to? }) => void-Fires with the formatted range.
onRangeChange(range: DateRange) => void-Escape hatch — fires with the raw DateRange.
numberOfMonthsnumber2Months rendered side by side.

DateBadge

PropTypeDefaultDescription
dateDate | string | number-The value to display (Date, ISO string, or epoch ms).
displayFormatstring"d MMM yyyy"date-fns pattern used to render the date.
timeZonestring-IANA zone to render in (e.g. "Australia/Sydney"). Defaults to local.
showZonebooleanfalseShow a leading zone-label chip (e.g. "GMT+10").
variantBadgeVariant"outline"Forwarded to the underlying Badge.

DateTag

PropTypeDefaultDescription
dateDate | string | number-The value to display.
displayFormatstring"d MMM yyyy"Pattern for the inline trigger text.
detailFormatstring"d MMM yyyy, h:mm:ss a"Pattern for the rows inside the hover card.
timeZonestring-Zone the value is shown in; the hover compares it to the viewer's local zone.
timeZoneLabelstring-Override the displayed zone's label.
relativebooleantrueShow the "x ago" header.