Date Picker

Type or paste a date, or choose a calendar day to update the field immediately. Date-only selection closes the popup and returns focus to its calendar action. Month and year navigation leaves the value unchanged. Escape or clicking outside closes the popup. The default value is YYYY-MM-DD; explicit local date-time, instant and zoned types preserve their clock precision and bound zone. Date-time popups keep the clock editable, committing each complete valid edit. Native fields remain usable before JavaScript.

Choose a date

Type or paste a date directly, or choose a calendar day to update the field immediately. The native form submits one canonical YYYY-MM-DD value.

Su

M

T

W

Th

F

S

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-date-picker/ui-date-picker.html"
>

<ui-date-picker
  label="Due date"
  name="due"
  value="2026-10-30"
  locale="en-US"
></ui-date-picker>
<script setup>
  import { UiDatePicker } from "@threadlabs/looma";
</script>

<template>
  <UiDatePicker
    label="Due date"
    name="due"
    value="2026-10-30"
    locale="en-US"
  />
</template>
import { UiDatePicker } from "@threadlabs/looma";

export default function Example() {
  return <UiDatePicker
    label="Due date"
    name="due"
    value="2026-10-30"
    locale="en-US"
  />;
}
/** @jsxImportSource preact */
import { UiDatePicker } from "@threadlabs/looma";

export default function Example() {
  return <UiDatePicker
    label="Due date"
    name="due"
    value="2026-10-30"
    locale="en-US"
  />;
}
<script>
  import { UiDatePicker } from "@threadlabs/looma";
</script>

<UiDatePicker
  label="Due date"
  name="due"
  value="2026-10-30"
  locale="en-US"
/>
import { Component } from "@angular/core";
import { UiDatePicker } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiDatePicker],
  template: `
    <span
      ui-date-picker
      [label]="'Due date'"
      [name]="'due'"
      [value]="'2026-10-30'"
      [locale]="'en-US'"
    ></span>
  `,
})
export default class Example {}

Preserve a local time

Calendar navigation preserves the existing clock and fractional precision. The time blocks and clock choices remain directly editable; the bound value retains its space separator.

Su

M

T

W

Th

F

S

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-date-picker/ui-date-picker.html"
>

<ui-date-picker
  type="datetime-local"
  value-format="space"
  label="Date and time"
  name="appointment"
  value="2026-10-30 14:30:45.125"
  locale="en-US"
></ui-date-picker>
<script setup>
  import { UiDatePicker } from "@threadlabs/looma";
</script>

<template>
  <UiDatePicker
    type="datetime-local"
    value-format="space"
    label="Date and time"
    name="appointment"
    value="2026-10-30 14:30:45.125"
    locale="en-US"
  />
</template>
import { UiDatePicker } from "@threadlabs/looma";

export default function Example() {
  return <UiDatePicker
    type="datetime-local"
    valueFormat="space"
    label="Date and time"
    name="appointment"
    value="2026-10-30 14:30:45.125"
    locale="en-US"
  />;
}
/** @jsxImportSource preact */
import { UiDatePicker } from "@threadlabs/looma";

export default function Example() {
  return <UiDatePicker
    type="datetime-local"
    valueFormat="space"
    label="Date and time"
    name="appointment"
    value="2026-10-30 14:30:45.125"
    locale="en-US"
  />;
}
<script>
  import { UiDatePicker } from "@threadlabs/looma";
</script>

<UiDatePicker
  type="datetime-local"
  valueFormat="space"
  label="Date and time"
  name="appointment"
  value="2026-10-30 14:30:45.125"
  locale="en-US"
/>
import { Component } from "@angular/core";
import { UiDatePicker } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiDatePicker],
  template: `
    <span
      ui-date-picker
      [type]="'datetime-local'"
      [valueFormat]="'space'"
      [label]="'Date and time'"
      [name]="'appointment'"
      [value]="'2026-10-30 14:30:45.125'"
      [locale]="'en-US'"
    ></span>
  `,
})
export default class Example {}

Edit an exact time

An instant is displayed and edited in an explicit zone, while the form submits UTC. Skipped or repeated wall-clock times are rejected unless disambiguation is chosen explicitly.

Su

M

T

W

Th

F

S

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-date-picker/ui-date-picker.html"
>

<ui-date-picker
  type="instant"
  time-zone="America/New_York"
  label="Date and time"
  name="appointment"
  value="2026-10-31T02:30:00Z"
  locale="en-US"
></ui-date-picker>
<script setup>
  import { UiDatePicker } from "@threadlabs/looma";
</script>

<template>
  <UiDatePicker
    type="instant"
    time-zone="America/New_York"
    label="Date and time"
    name="appointment"
    value="2026-10-31T02:30:00Z"
    locale="en-US"
  />
</template>
import { UiDatePicker } from "@threadlabs/looma";

export default function Example() {
  return <UiDatePicker
    type="instant"
    timeZone="America/New_York"
    label="Date and time"
    name="appointment"
    value="2026-10-31T02:30:00Z"
    locale="en-US"
  />;
}
/** @jsxImportSource preact */
import { UiDatePicker } from "@threadlabs/looma";

export default function Example() {
  return <UiDatePicker
    type="instant"
    timeZone="America/New_York"
    label="Date and time"
    name="appointment"
    value="2026-10-31T02:30:00Z"
    locale="en-US"
  />;
}
<script>
  import { UiDatePicker } from "@threadlabs/looma";
</script>

<UiDatePicker
  type="instant"
  timeZone="America/New_York"
  label="Date and time"
  name="appointment"
  value="2026-10-31T02:30:00Z"
  locale="en-US"
/>
import { Component } from "@angular/core";
import { UiDatePicker } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiDatePicker],
  template: `
    <span
      ui-date-picker
      [type]="'instant'"
      [timeZone]="'America/New_York'"
      [label]="'Date and time'"
      [name]="'appointment'"
      [value]="'2026-10-31T02:30:00Z'"
      [locale]="'en-US'"
    ></span>
  `,
})
export default class Example {}

Keep the appointment's zone

A zoned binding saves the date, clock, offset and region together. Its bracketed zone supplies the editing zone, so no separate time-zone prop is needed. Date-only fields omit type and save just YYYY-MM-DD.

Su

M

T

W

Th

F

S

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-date-picker/ui-date-picker.html"
>

<ui-date-picker
  type="zoned"
  label="Appointment"
  name="appointment"
  value="2026-10-30T09:00-07:00[America/Vancouver]"
  locale="en-US"
></ui-date-picker>
<script setup>
  import { UiDatePicker } from "@threadlabs/looma";
</script>

<template>
  <UiDatePicker
    type="zoned"
    label="Appointment"
    name="appointment"
    value="2026-10-30T09:00-07:00[America/Vancouver]"
    locale="en-US"
  />
</template>
import { UiDatePicker } from "@threadlabs/looma";

export default function Example() {
  return <UiDatePicker
    type="zoned"
    label="Appointment"
    name="appointment"
    value="2026-10-30T09:00-07:00[America/Vancouver]"
    locale="en-US"
  />;
}
/** @jsxImportSource preact */
import { UiDatePicker } from "@threadlabs/looma";

export default function Example() {
  return <UiDatePicker
    type="zoned"
    label="Appointment"
    name="appointment"
    value="2026-10-30T09:00-07:00[America/Vancouver]"
    locale="en-US"
  />;
}
<script>
  import { UiDatePicker } from "@threadlabs/looma";
</script>

<UiDatePicker
  type="zoned"
  label="Appointment"
  name="appointment"
  value="2026-10-30T09:00-07:00[America/Vancouver]"
  locale="en-US"
/>
import { Component } from "@angular/core";
import { UiDatePicker } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiDatePicker],
  template: `
    <span
      ui-date-picker
      [type]="'zoned'"
      [label]="'Appointment'"
      [name]="'appointment'"
      [value]="'2026-10-30T09:00-07:00[America/Vancouver]'"
      [locale]="'en-US'"
    ></span>
  `,
})
export default class Example {}

API

Package: @threadlabs/looma · Native root: span

Attributes

NameDescriptionPropertyTypeDefaultAllowed values
allowed-datesAllowed ISO dates, unioned with allowedRanges. Omission imposes no allow restriction; an explicitly empty allow set permits nothing.allowedDateslist(string)——
allowed-rangesAllowed inclusive ISO-date intervals, unioned with allowedDates.allowedRangeslist(object)
  • [].start: string (required)
  • [].end: string (required)
——
disabledPrevents editing and omits the value from submission.disabledbooleanfalse—
disabled-datesUnavailable ISO dates, applied in the editing zone for exact values.disabledDateslist(string)[]—
disabled-rangesUnavailable inclusive ISO-date intervals.disabledRangeslist(object)
  • [].start: string (required)
  • [].end: string (required)
[]—
disabled-weekdaysUnavailable ISO weekdays, from 1 (Monday) to 7 (Sunday).disabledWeekdayslist(integer)[]—
disambiguationHow zoned edits resolve a skipped or repeated wall-clock time. Reject leaves the draft visible with a validation error.disambiguationkeywordrejectreject, earlier, later, compatible
display-optionsIntl display options while unfocused. Focusing uses the numeric editing grammar; formatting does not change the binding. Calendar identity and editing timezone stay with the field.displayOptionsobject
  • dateStyle: keyword
  • timeStyle: keyword
  • weekday: keyword
  • era: keyword
  • year: keyword
  • month: keyword
  • day: keyword
  • hour: keyword
  • minute: keyword
  • second: keyword
  • timeZoneName: keyword
  • dayPeriod: keyword
  • hourCycle: keyword
  • localeMatcher: string
  • formatMatcher: string
  • fractionalSecondDigits: integer
  • hour12: boolean
  • numberingSystem: string
——
formOptional ID of a form outside this component’s ancestor tree.formstring—
granularitySmallest displayed time unit. Existing nonzero seconds and fractions remain editable without precision loss.granularitykeywordminuteminute, second
hour-cycleIntl hour cycle. Omit to follow locale conventions.hourCyclekeyword—h11, h12, h23, h24
input-idID of the active native input for an authored label's for attribute, preserved across upgrade.inputIdstring—
invalidExternal invalid state, independent of parsing and availability.invalidbooleanfalse—
labelOptional accessible name. Prefer an authored visible label associated with input-id; a supplied label overrides that name.labelstring—
localeExplicit Intl locale for numeric editing order, digits and display. ISO input is always accepted.localestringen-US—
maxInclusive maximum in the bound value's format.maxstring—
minInclusive minimum in the bound value's format.minstring—
modelServer-prepared civil date/time projection owned by the component module.modelobject
  • date: string (required)
  • time: string (required)
  • minDate: string (required)
  • maxDate: string (required)
  • weekStartsOn: integer (required)
  • allowedDates: list(string) (required)
  • allowedRanges: list(object) (required)
  • allowedRanges[].start: string (required)
  • allowedRanges[].end: string (required)
——
month-labelAccessible name of the month navigation toggle.monthLabelstringChoose month—
nameNative form field name. The enhanced field submits its canonical value.namestring—
next-labelAccessible name of the next-page action.nextLabelstringNext—
picker-labelAccessible name of the calendar action and its dialog.pickerLabelstringChoose date—
placeholderOptional editing hint. A placeholder never replaces the label.placeholderstring—
previous-labelAccessible name of the previous-page action.previousLabelstringPrevious—
readonlyRetains selection and submission while preventing edits.readonlybooleanfalse—
requiredRequires a complete value.requiredbooleanfalse—
sizeInput's shared size scale.sizekeywordmdsm, md, lg
time-labelLabel of the time field.timeLabelstringTime—
time-zoneDisplay/editing zone for instant values, required for localized instant editing. Zoned values otherwise use their saved zone; an override preserves that saved zone. Required when creating a new zoned value. Date and local date-time bindings remain without a zone.timeZonestring—
todayOptional YYYY-MM-DD date to mark as today in the calendar.todaystring—
typeThe value's meaning and export format. Date is the default and exports only YYYY-MM-DD, without a time or timezone. Local date-time is a wall-clock value; instant uses a UTC timestamp; zoned retains a named zone. Time-zone and display options alone never change this type.typekeyworddatedate, datetime-local, instant, zoned
valueInitial canonical value, and a replacement when changed externally. Valid edits update live state and emit input/change; a form reset returns to the last external value.valuestring—
value-formatLocal date-time bindings use T by default; space emits YYYY-MM-DD HH:ss. Other types retain their ISO form.valueFormatkeywordisoiso, space
week-starts-onWeek order override using ISO weekdays: Sunday 7, Saturday 6, or Monday 1. Omission follows the locale's week information, with Sunday as the fallback when unavailable.weekStartsOninteger——
year-labelAccessible name of the year navigation toggle and direct year input.yearLabelstringChoose year—

Framework props

NameTypeDefaultAllowed values
allowedDatesreadonly (string)[]——
allowedRangesreadonly ({ readonly start: string; readonly end: string })[]
  • [].start: string (required)
  • [].end: string (required)
——
disabledbooleanfalse—
disabledDatesreadonly (string)[][]—
disabledRangesreadonly ({ readonly start: string; readonly end: string })[]
  • [].start: string (required)
  • [].end: string (required)
[]—
disabledWeekdaysreadonly (number)[][]—
disambiguation"reject" | "earlier" | "later" | "compatible"rejectreject, earlier, later, compatible
displayOptions{ readonly dateStyle?: "full" | "long" | "medium" | "short" | null; readonly timeStyle?: "full" | "long" | "medium" | "short" | null; readonly weekday?: "long" | "short" | "narrow" | null; readonly era?: "long" | "short" | "narrow" | null; readonly year?: "numeric" | "2-digit" | null; readonly month?: "numeric" | "2-digit" | "long" | "short" | "narrow" | null; readonly day?: "numeric" | "2-digit" | null; readonly hour?: "numeric" | "2-digit" | null; readonly minute?: "numeric" | "2-digit" | null; readonly second?: "numeric" | "2-digit" | null; readonly timeZoneName?: "long" | "short" | "shortOffset" | "longOffset" | "shortGeneric" | "longGeneric" | null; readonly dayPeriod?: "long" | "short" | "narrow" | null; readonly hourCycle?: "h11" | "h12" | "h23" | "h24" | null; readonly localeMatcher?: "lookup" | "best fit" | null; readonly formatMatcher?: "basic" | "best fit" | null; readonly fractionalSecondDigits?: number | null; readonly hour12?: boolean | null; readonly numberingSystem?: string | null }
  • dateStyle: keyword
  • timeStyle: keyword
  • weekday: keyword
  • era: keyword
  • year: keyword
  • month: keyword
  • day: keyword
  • hour: keyword
  • minute: keyword
  • second: keyword
  • timeZoneName: keyword
  • dayPeriod: keyword
  • hourCycle: keyword
  • localeMatcher: string
  • formatMatcher: string
  • fractionalSecondDigits: integer
  • hour12: boolean
  • numberingSystem: string
——
formstring—
granularity"minute" | "second"minuteminute, second
hourCycle"h11" | "h12" | "h23" | "h24"—h11, h12, h23, h24
inputIdstring—
invalidbooleanfalse—
labelstring—
localestringen-US—
maxstring—
minstring—
model{ readonly date: string; readonly time: string; readonly minDate: string; readonly maxDate: string; readonly weekStartsOn: number; readonly allowedDates: readonly (string)[]; readonly allowedRanges: readonly ({ readonly start: string; readonly end: string })[] }
  • date: string (required)
  • time: string (required)
  • minDate: string (required)
  • maxDate: string (required)
  • weekStartsOn: integer (required)
  • allowedDates: list(string) (required)
  • allowedRanges: list(object) (required)
  • allowedRanges[].start: string (required)
  • allowedRanges[].end: string (required)
——
monthLabelstringChoose month—
namestring—
nextLabelstringNext—
pickerLabelstringChoose date—
placeholderstring—
previousLabelstringPrevious—
readonlybooleanfalse—
requiredbooleanfalse—
size"sm" | "md" | "lg"mdsm, md, lg
timeLabelstringTime—
timeZonestring—
todaystring—
type"date" | "datetime-local" | "instant" | "zoned"datedate, datetime-local, instant, zoned
valuestring—
valueFormat"iso" | "space"isoiso, space
weekStartsOnnumber——
yearLabelstringChoose year—

Events

NameDetailDescription
changeobject
  • value: string (required)
  • trigger: keyword (required)
Emitted when a toggleable control changes checked state.
closeobject
  • open: boolean (required)
  • reason: keyword (required)
  • trigger: keyword (required)
Emitted when the component transitions to a closed state.
inputobject
  • value: string (required)
  • trigger: keyword (required)
Emitted with the declared detail payload.
openobject
  • open: boolean (required)
  • reason: keyword (required)
  • trigger: keyword (required)
Emitted when the component transitions to an open state.
query-changeobject
  • query: string (required)
Emitted with the declared detail payload.
validation-changeobject
  • invalid: boolean (required)
  • message: string (required)
Emitted with the declared detail payload.

Slots

No slots.

Design tokens

Set shared theme properties on a theme boundary. Component hooks apply only to their owning component.

Component tokens

No component tokens.

Shared tokens

No shared tokens.