Skip to content
omaris

Inputs

Date Range Field

A date-range input for a dashboard's filter bar: a field that reads "Mar 3 – 9, 2026" and opens two months side by side with a rail of shortcuts — Today, Last 7 days, This month — beside them.

import { DateRangeField } from 'omaris'
Learn

Examples

Basic

A dashboard's period filter: two months and a rail of shortcuts on a desktop, one month, chips and an Apply button in a sheet on a phone. The value is { start, end }, both ends inclusive.

<script lang="ts">	import { DateRangeField, addDays, startOfDay, type DateRange } from 'omaris';​	const today = startOfDay(new Date());	let period = $state<DateRange | null>({ start: addDays(today, -6), end: today });</script>​<DateRangeField class="w-72 max-w-full" label="Period" bind:value={period} max={today} />

Presets

presets replaces the shortcuts — built from the same date helpers, clamped to min and max when chosen. Pass [] for none, and months={1} for a narrower panel.

<script lang="ts">	import { DateRangeField, addDays, startOfDay, type DatePreset } from 'omaris';​	const today = startOfDay(new Date());​	const AHEAD: DatePreset[] = [		{ label: 'Next 7 days', range: () => ({ start: today, end: addDays(today, 6) }) },		{ label: 'Next 14 days', range: () => ({ start: today, end: addDays(today, 13) }) },		{ label: 'Next 30 days', range: () => ({ start: today, end: addDays(today, 29) }) }	];</script>​<DateRangeField class="w-72 max-w-full" label="Booking window" presets={AHEAD} min={today} /><DateRangeField class="w-72 max-w-full" label="Any dates" presets={[]} months={1} />

States

The field's own states are a text field's: variants, sizes, invalid with its message, disabled.

Pick at most 90 days.

<script lang="ts">	import { DateRangeField } from 'omaris';​	const MARCH = { start: new Date(2026, 2, 3), end: new Date(2026, 2, 9) };</script>​<DateRangeField class="w-64 max-w-full" variant="filled" size="sm" label="Filled" value={MARCH} /><DateRangeField	class="w-64 max-w-full"	label="Invalid"	invalid	supportingText="Pick at most 90 days."/><DateRangeField class="w-64 max-w-full" label="Disabled" disabled value={MARCH} />

Overridden

classes covers the frame and the presets; labels renames the words the field says itself. A name posts the range as an ISO interval, 2026-03-03/2026-03-09.

<script lang="ts">	import { DateRangeField } from 'omaris';</script>​<form class="w-56 max-w-full">	<DateRangeField		label="Billing cycle"		name="cycle"		value={{ start: new Date(2026, 2, 3), end: new Date(2026, 2, 9) }}		labels={{ presets: 'Quick ranges', apply: 'Use range' }}		classes={{ field: 'bg-surface-container', preset: 'rounded-shape-sm', value: 'font-medium' }}	/></form>

When to use it

Use it for

  • The period filter at the top of a dashboard or a report: "Mar 3 – 9, 2026", with Today, Last 7 days, Last 30 days, This month, Last month and This year one press away.
  • A span in a form — a leave request, a campaign's run, a rental — where the two ends belong to one question.
  • Commit-on-Apply on a phone: the sheet keeps a draft, so a thumb that lands on the wrong day changes nothing until Apply.

Not for

  • One date → Date Field.
  • A range picked on the page itself, with no field → Calendar with mode="range".
  • A handful of fixed periods and nothing else — "7d / 30d / 90d" → Segmented Button. A calendar behind a field is overhead when nobody picks a custom range.
  • A range of times within a day → two TimePickers in Picker.

Do

  • Set max={today} on a filter over data that ends today. The presets clamp to it, so "This month" becomes month-to-date.
  • Replace the presets with the periods your users actually compare — presets takes { label, range }, and the date helpers build the ranges.
  • Translate labels and the preset labels together when the page is not in English; the calendar translates itself.
  • Show the chosen period somewhere in the view it filters, not only in the field — the chart's subtitle, the export's filename.

Don't

  • Keep the default presets when min rules most of them out. A rail of greyed shortcuts reads as broken.
  • Expect value to change on the first calendar press. It changes when the range is whole — the second press on a desktop, Apply on a phone.
  • Put two of these side by side for "compare to". Say what is being compared and give the second one its own label.

API

DateRangeField

A date-range input for a dashboard's filter bar: a field that reads "Mar 3 – 9, 2026" and opens two months side by side with a rail of shortcuts — Today, Last 7 days, This month — beside them.

On a desktop the second press on the calendar commits the range and closes, and a shortcut commits at once. On a phone it is a bottom sheet with one month and a row of shortcut chips, and nothing changes until Apply — a thumb that lands on the wrong day costs nothing.

The value is { start, end } at local midnight, both ends inclusive, or null. With a name it posts as an ISO interval, 2026-03-03/2026-03-09.

import { DateRangeField } from 'omaris'
<DateRangeField label="Period" bind:value={period} max={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.

body
Presets and calendar together, inside the popup.
presets
The shortcut rail: a column at the start on a wide screen, a scrolling row otherwise.
preset
One shortcut.
footer
Cancel and Apply, pinned under the sheet on a phone.
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

DateRange | null

The range, or null. Bindable.

variant

Defaults to 'outline'

DateFieldVariant

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

size

Defaults to 'default'

DateFieldSize

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

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 range'

string

Shown, greyed, while there is no range.

format

Defaults to { dateStyle: 'medium' }

Intl.DateTimeFormatOptions

Intl.DateTimeFormat options for the two ends, joined by formatRange.

presets

Defaults to defaultDatePresets

DatePreset[]

Shortcuts beside the calendar — Today through This year unless you pass your own, or [] for none. Each is clamped to min and max when chosen, and one that falls wholly outside them is disabled.

months

Defaults to 2

1 | 2

Months side by side on a desktop. A phone always gets one.

min
Date

Earliest selectable day.

max
Date

Latest selectable day — today for a filter over data that ends now.

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 range.

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.

labels
DateRangeFieldLabels

The words the field says itself — the presets group's name, Apply, Cancel.

onchange
(value: DateRange | null) => void

Fires when a range is committed or cleared.

class
string

Merged onto the root wrapper.

classes
DateRangeFieldClasses

Per-part Tailwind overrides — the frame's parts and the presets'.

calendarClasses
CalendarClasses

Per-part overrides for the calendar inside the popup.

ref bindable

Defaults to null

HTMLButtonElement | null

The trigger button.