Inputs

Input DateTime

Date and time input with segmented editing, a hidden field for native forms, and optional calendar selection.

Overview

InputDatetime composes Input Group and, for date / datetime modes, Popover and Calendar. The visible value is split into focusable segments (one per date/time field in your format). A hidden <input> mirrors the composed string for native form posts. Use onValueChange when a full Date is committed: all segments are valid, then Enter, blur after completion, or a calendar pick.

In date and datetime modes, the trailing button opens a Calendar popover for day selection; time mode has no calendar.

Key bindings

KeyBehavior
Deletes the last digit in the focused segment. If the segment is empty, focus moves to the previous segment.
Clears the focused segment. The next digit typed replaces the whole segment (same as focusing fresh).
/Move focus to the previous or next segment (at ends of the field, the key has no effect).
Commits the current composed string: if every segment is filled and the value parses for the format, onValueChange runs with the resulting Date. Works from a segment or from the surrounding control.
Moves through segments and the calendar button (in date / datetime modes) in focus order.
blurLeaving a segment commits the same way as (when the value is complete and valid).

Custom props

PropTypeDescription
mode'date' | 'time' | 'datetime'Defaults to 'datetime'. Narrows which field tokens from format are editable (date parts, time parts, or both).
formatstringPattern for editable segments (y, M, d, H, m, s runs, as in date-fns) and static text between them (e.g. yyyy/MM/dd - HH:mm). If omitted, defaults are yyyy/MM/dd (date), HH:mm (time), and yyyy/MM/dd HH:mm (datetime).
valueDate | string | nullControlled value: a Date or an ISO-like or formatted string parseable with format.
onValueChange(date: Date | null) => voidFires when a committed, valid Date is available (see Overview and Key bindings).
size'xs' | 'sm' | 'default' | 'lg'Optional. Input Group size: shell height, segment padding/text, and calendar control scale together. This is not the HTML size attribute (that prop is not forwarded to the hidden input).

Install

Configure your registry in components.json:

{
  "registries": {
    "@uxio": "https://ui.uxio.dev/r/styles/{style}/{name}.json"
  }
}

Then run:

npx shadcn@latest add @uxio/input-datetime

This pulls input-group, calendar, and popover as registry dependencies. The correct variant (Base UI or Radix) follows your components.json style.

Usage

Controlled datetime

import * as React from "react"

import { InputDatetime } from "@/components/ui/input-datetime"

export function ScheduledAtField() {
  const [value, setValue] = React.useState<Date | null>(null)

  return (
    <InputDatetime mode="datetime" value={value ?? undefined} onValueChange={setValue} />
  )
}

Date-only with custom format

import * as React from "react"

import { InputDatetime } from "@/components/ui/input-datetime"

export function BirthDateField() {
  const [value, setValue] = React.useState<Date | null>(null)

  return (
    <InputDatetime
      mode="date"
      format="dd/MM/yyyy"
      value={value ?? undefined}
      onValueChange={setValue}
    />
  )
}

Time-only

import * as React from "react"

import { InputDatetime } from "@/components/ui/input-datetime"

export function TimeField() {
  const [value, setValue] = React.useState<Date | null>(null)

  return (
    <InputDatetime mode="time" format="HH:mm" value={value ?? undefined} onValueChange={setValue} />
  )
}

Examples

Date mode (mode="date")

00000000

Committed (onValueChange):

Hidden string (onChange):

Time mode (mode="time")

0000

Committed time: Fill HH:mm or pick a day in the calendar (reference date).

Datetime mode (mode="datetime")

000000000000

Controlled value:

Size variants

Use size so the field aligns with InputGroup and Input dimensions. Segment padding and text scale with the group.

xs

000000000000

sm

000000000000

default

000000000000

lg

000000000000