Skip to content
omaris

Inputs

Date Field

A date input: a field that shows the date in the page's language and opens a Calendar to change it — anchored under the field on a desktop, in a bottom sheet on a phone, where a popover would be a thumb's width from the edge.

import { DateField } from 'omaris'
Learn

Examples

Basic

A field that opens a calendar — under the field on a desktop, in a bottom sheet on a phone. The value is a Date at local midnight, or null.

<script lang="ts">	import { DateField } from 'omaris';​	let due = $state<Date | null>(null);</script>​<DateField class="w-64 max-w-full" label="Due date" bind:value={due} />

States

The same frame, sizes and states as a text field, so a form that mixes the two validates as one thing. min, max and isDateDisabled grey days out in the calendar rather than rejecting them after the fact.

Weekdays, next 30 days

Pick a start date.

<script lang="ts">	import { DateField, addDays, startOfDay } from 'omaris';​	const today = startOfDay(new Date());	const weekend = (date: Date) => date.getDay() === 0 || date.getDay() === 6;</script>​<DateField	class="w-56 max-w-full"	variant="filled"	label="Delivery"	min={today}	max={addDays(today, 30)}	isDateDisabled={weekend}	supportingText="Weekdays, next 30 days"/><DateField	class="w-56 max-w-full"	label="Start date"	required	invalid	supportingText="Pick a start date."/><DateField class="w-56 max-w-full" label="Signed" disabled value={today} />

Format and locale

format is Intl.DateTimeFormat options for the text in the field, and locale decides the names and the first weekday. Western digits either way.

<script lang="ts">	import { DateField } from 'omaris';​	let meeting = $state<Date | null>(new Date(2026, 2, 12));	let arabic = $state<Date | null>(new Date(2026, 2, 12));</script>​<DateField	class="w-64 max-w-full"	label="Meeting"	format={{ weekday: 'long', day: 'numeric', month: 'long' }}	bind:value={meeting}/><div class="w-64 max-w-full" dir="rtl" lang="ar-IQ">	<DateField		label="الموعد"		locale="ar-IQ"		placeholder="اختر تاريخًا"		format={{ dateStyle: 'long' }}		bind:value={arabic}	/></div>

Overridden

classes reaches the frame's parts and calendarClasses the calendar's. A name posts the date as YYYY-MM-DD, so the field works in a plain form.

<script lang="ts">	import { DateField } from 'omaris';</script>​<form class="w-48 max-w-full">	<DateField		label="Invoice date"		name="invoice-date"		size="sm"		format={{ year: 'numeric', month: '2-digit', day: '2-digit' }}		value={new Date(2026, 2, 12)}		classes={{ field: 'rounded-full', value: 'font-mono', icon: 'text-primary' }}		calendarClasses={{ face: 'rounded-shape-sm' }}	/></form>

When to use it

Use it for

  • A date in a form: a due date, a start date, a delivery day. It reads as text until pressed, then opens a calendar under the field — or, on a phone, in a bottom sheet where a thumb can reach it.
  • A date that should read in the page's language, with Western digits, without anyone writing a formatter: format takes Intl options.
  • A form posted the plain way: with name, the date goes as YYYY-MM-DD.

Not for

  • A span of dates → Date Range Field.
  • A calendar that stays open on the page → Calendar.
  • A birthday or any date years away → DatePicker in Picker; three wheels beat forty pages of months.
  • A time, or a date with a time → TimePicker or DateTimePicker in Picker.
  • A date people know by heart and type faster than they pick — an ID's expiry on a data-entry screen → an Input with type="date".

Do

  • Give it a label, and a placeholder that says what is missing when it is empty — "Pick a delivery day" rather than a format mask.
  • Put the valid window in min, max and isDateDisabled, so the calendar greys out what cannot be picked instead of the form rejecting it.
  • Use the same variant and size as the text fields around it; they are the same frame.
  • Turn clearable off when the date is required — an × that empties a field that cannot be empty is a trap.

Don't

  • Pass it a string. The value is a Date at local midnight, or null.
  • Use it as a filter chip in a toolbar. A range filter is Date Range Field; a single-day filter still wants a label someone can read.
  • Set mobileQuery wider than a phone. The sheet is for a thumb; a tablet is better served by the popover.

Quick reference

variant
  • outline (default)
  • filled
  • ghost
size
  • sm
  • default (default)
  • lg

API

DateField

A date input: a field that shows the date in the page's language and opens a Calendar to change it — anchored under the field on a desktop, in a bottom sheet on a phone, where a popover would be a thumb's width from the edge.

It looks and behaves like Input — the same variants, sizes, label, supporting text and invalid state — so a form reads as one thing. The value is a Date at local midnight, or null; with a name it is also posted as YYYY-MM-DD.

Keyboard: Enter, Space or ↓ opens the calendar with focus on the date, the arrows walk it, Enter picks and closes, Escape closes without picking. Backspace on the field clears it.

import { DateField } from 'omaris'
<DateField label="Due" bind:value={due} min={new Date()} />

Parts

Every element this renders is reachable from outside. Pass Tailwind for one part as classes={{ part: '…' }}; class covers the root and is merged last, so it always wins.

root
Wrapper: label, field, supporting text.
field
The frame: border, background, height.
control
The button that opens the calendar: the whole frame, minus the clear button.
value
The formatted date, or the placeholder.
placeholder
Added to value while there is no date.
icon
The calendar glyph at the end.
action
The clear button.
label
The label above the frame.
support
The helper or error line under the frame.
panel
The popover the calendar opens in, on a desktop.
sheet
The bottom sheet it opens in, on a phone.

Props

value bindable

Defaults to null

Date | null

The date, at local midnight, or null. Bindable.

variant

Defaults to 'outline'

DateFieldVariant

outline, filled or ghost — the same frames as Input.

outline
The default: a hairline frame on the page background.
filled
Softer — a tinted well with no border until you touch it.
ghost
No frame at all, for fields nested in another surface.
size

Defaults to 'default'

DateFieldSize

sm, default or lg — the same heights as Input.

sm
default
lg
label
string

Label above the field.

required

Defaults to false

boolean

Marks the label required.

supportingText
string

Helper line under the field. Turns into the error text when invalid.

invalid

Defaults to false

boolean

Marks the field invalid and wires up aria-invalid.

placeholder

Defaults to 'Select a date'

string

Shown, greyed, while there is no date.

format

Defaults to { dateStyle: 'medium' }

Intl.DateTimeFormatOptions

How the date reads in the field. Intl.DateTimeFormat options, with Western digits added — { dateStyle: 'long' }, or { weekday: 'short', day: 'numeric', month: 'short' }.

min
Date

Earliest selectable day.

max
Date

Latest selectable day.

isDateDisabled
(date: Date) => boolean

Days that cannot be picked.

locale
string

BCP-47 tag for the field and the calendar. Defaults to <html lang>.

weekStartsOn
Weekday

0 is Sunday. Defaults to the locale's first day.

clearable

Defaults to true

boolean

Show an × that empties the field once it has a date.

open bindable

Defaults to false

boolean

Whether the calendar is open. Bindable.

mobileQuery

Defaults to '(max-width: 639px)'

string

What counts as a phone, where the calendar opens in a bottom sheet.

onchange
(value: Date | null) => void

Fires after a pick or a clear.

class
string

Merged onto the root wrapper.

classes
DateFieldClasses

Per-part Tailwind overrides. class still covers the root.

calendarClasses
CalendarClasses

Per-part overrides for the calendar inside the popup.

ref bindable

Defaults to null

HTMLButtonElement | null

The trigger button.