Date Field

The default date type exports only YYYY-MM-DD. Explicit time, local date-time, instant and zoned types keep their own value semantics; display formatting never changes the binding type. Editable dates and times with canonical string values, localized numeric typing, Temporal validation, inclusive bounds and declarative date availability. Native inputs remain usable before upgrade; precision and space-separated local values use text fallbacks to retain their serialization. Enhanced input preserves incomplete drafts and submits canonical values. A set-value CustomEvent with canonical detail.value commits an explicit choice and replaces the draft, including when its accepted value is unchanged.

Type a date

ISO paste and the declared locale's date order are accepted. Focus uses numeric entry; the unfocused field can use a longer Intl display format.

Code

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

<ui-date-field
  label="Due date"
  name="due"
  value="2026-10-30"
  locale="en-US"
  display-options="{&quot;dateStyle&quot;:&quot;long&quot;}"
></ui-date-field>
<script setup>
  import { UiDateField } from "@threadlabs/looma";
</script>

<template>
  <UiDateField
    label="Due date"
    name="due"
    value="2026-10-30"
    locale="en-US"
    :display-options="{ dateStyle: 'long' }"
  />
</template>
import { UiDateField } from "@threadlabs/looma";

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

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

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

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

Available dates

Bounds and allowed intervals intersect; disabled dates and weekdays take precedence. Unavailable typed values remain visible with native validation.

Code

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

<ui-date-field
  label="Appointment date"
  min="2026-10-01"
  max="2026-12-31"
  disabled-dates="[&quot;2026-11-11&quot;]"
  disabled-weekdays="[6,7]"
></ui-date-field>
<script setup>
  import { UiDateField } from "@threadlabs/looma";
</script>

<template>
  <UiDateField
    label="Appointment date"
    min="2026-10-01"
    max="2026-12-31"
    :disabled-dates="['2026-11-11']"
    :disabled-weekdays="[6, 7]"
  />
</template>
import { UiDateField } from "@threadlabs/looma";

export default function Example() {
  return <UiDateField
    label="Appointment date"
    min="2026-10-01"
    max="2026-12-31"
    disabledDates={["2026-11-11"]}
    disabledWeekdays={[6,7]}
  />;
}
/** @jsxImportSource preact */
import { UiDateField } from "@threadlabs/looma";

export default function Example() {
  return <UiDateField
    label="Appointment date"
    min="2026-10-01"
    max="2026-12-31"
    disabledDates={["2026-11-11"]}
    disabledWeekdays={[6,7]}
  />;
}
<script>
  import { UiDateField } from "@threadlabs/looma";
</script>

<UiDateField
  label="Appointment date"
  min="2026-10-01"
  max="2026-12-31"
  disabledDates={["2026-11-11"]}
  disabledWeekdays={[6,7]}
/>
import { Component } from "@angular/core";
import { UiDateField } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiDateField],
  template: `
    <span
      ui-date-field
      [label]="'Appointment date'"
      [min]="'2026-10-01'"
      [max]="'2026-12-31'"
      [disabledDates]="['2026-11-11']"
      [disabledWeekdays]="[6, 7]"
    ></span>
  `,
})
export default class Example {}

Wall-clock and exact time

A time of day has no date or zone. An exact instant uses an explicit editing zone; localized formatting never changes its identity.

Code

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

<ui-stack
  gap="s"
>
  <ui-date-field
    type="time"
    label="Opening time"
    value="09:30"
    min="08:00"
    max="18:00"
    locale="en-US"
  ></ui-date-field>
  <ui-date-field
    type="instant"
    label="Meeting time"
    value="2026-10-30T18:30:00Z"
    time-zone="America/New_York"
    locale="en-US"
  ></ui-date-field>
</ui-stack>
<script setup>
  import { UiDateField, UiStack } from "@threadlabs/looma";
</script>

<template>
  <UiStack
    gap="s"
  >
    <UiDateField
      type="time"
      label="Opening time"
      value="09:30"
      min="08:00"
      max="18:00"
      locale="en-US"
    />
    <UiDateField
      type="instant"
      label="Meeting time"
      value="2026-10-30T18:30:00Z"
      time-zone="America/New_York"
      locale="en-US"
    />
  </UiStack>
</template>
import { UiDateField, UiStack } from "@threadlabs/looma";

export default function Example() {
  return <UiStack
    gap="s"
  >
    <UiDateField
      type="time"
      label="Opening time"
      value="09:30"
      min="08:00"
      max="18:00"
      locale="en-US"
    />
    <UiDateField
      type="instant"
      label="Meeting time"
      value="2026-10-30T18:30:00Z"
      timeZone="America/New_York"
      locale="en-US"
    />
  </UiStack>;
}
/** @jsxImportSource preact */
import { UiDateField, UiStack } from "@threadlabs/looma";

export default function Example() {
  return <UiStack
    gap="s"
  >
    <UiDateField
      type="time"
      label="Opening time"
      value="09:30"
      min="08:00"
      max="18:00"
      locale="en-US"
    />
    <UiDateField
      type="instant"
      label="Meeting time"
      value="2026-10-30T18:30:00Z"
      timeZone="America/New_York"
      locale="en-US"
    />
  </UiStack>;
}
<script>
  import { UiDateField, UiStack } from "@threadlabs/looma";
</script>

<UiStack
  gap="s"
>
  <UiDateField
    type="time"
    label="Opening time"
    value="09:30"
    min="08:00"
    max="18:00"
    locale="en-US"
  />
  <UiDateField
    type="instant"
    label="Meeting time"
    value="2026-10-30T18:30:00Z"
    timeZone="America/New_York"
    locale="en-US"
  />
</UiStack>
import { Component } from "@angular/core";
import { UiDateField, UiStack } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiStack, UiDateField],
  template: `
    <div
      ui-stack
      [gap]="'s'"
    >
      <span
        ui-date-field
        [type]="'time'"
        [label]="'Opening time'"
        [value]="'09:30'"
        [min]="'08:00'"
        [max]="'18:00'"
        [locale]="'en-US'"
      ></span>
      <span
        ui-date-field
        [type]="'instant'"
        [label]="'Meeting time'"
        [value]="'2026-10-30T18:30:00Z'"
        [timeZone]="'America/New_York'"
        [locale]="'en-US'"
      ></span>
    </div>
  `,
})
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—
nameNative form field name. The enhanced field submits its canonical value.namestring—
placeholderOptional editing hint. A placeholder never replaces the label.placeholderstring—
readonlyRetains selection and submission while preventing edits.readonlybooleanfalse—
requiredRequires a complete value.requiredbooleanfalse—
sizeInput's shared size scale.sizekeywordmdsm, md, lg
time-zoneDisplay/editing zone for instant values, required for localized instant editing. Zoned values otherwise use their saved zone; local typing through an override preserves that saved zone. Required for a new zoned value. Date, time and local date-time bindings remain without a zone.timeZonestring—
typeThe value's meaning and export format. Date is the default and exports only YYYY-MM-DD, without a time or timezone. Time and local date-time remain wall-clock values; instant uses a UTC timestamp; zoned retains a named zone. Display options alone never change this type.typekeyworddatedate, time, 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

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—
namestring—
placeholderstring—
readonlybooleanfalse—
requiredbooleanfalse—
size"sm" | "md" | "lg"mdsm, md, lg
timeZonestring—
type"date" | "time" | "datetime-local" | "instant" | "zoned"datedate, time, datetime-local, instant, zoned
valuestring—
valueFormat"iso" | "space"isoiso, space

Events

NameDetailDescription
changeobject
  • value: string (required)
  • trigger: keyword (required)
Emitted when a toggleable control changes checked state.
inputobject
  • value: string (required)
  • trigger: keyword (required)
Emitted with the declared detail payload.
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.