Calendar
Selection values and events always contain only a YYYY-MM-DD civil date, with no time or timezone. Temporal calendar navigation with one day-grid tab stop, locale-aware Gregorian labels, direct month/year selection and typed year navigation. Availability combines inclusive bounds, allowed dates/ranges and disabled dates/ranges/ISO weekdays. Navigation leaves selection unchanged; input and change report a changed selection, and select reports every accepted day activation. Compose with Date Field for typed date entry and native form submission. The server-safe model producer is prepared through HTML Next's existing module binding hooks. Day choices use centered circular ghost hover/selection paint; unavailable dates retain transparent surfaces and muted text. Week order follows locale information, falling back to Sunday first. week-starts-on overrides it, including Sunday (7), Saturday (6), or Monday (1). Sunday and Saturday columns have a faint theme-derived surface. Month/year controls provide the visible heading.
Choose a date
Open the month or year heading to jump directly. Arrow keys move through available dates; Page Up/Down changes month, and Shift changes year.
Su
M
T
W
Th
F
S
No available dates this month.
Code
<link
rel="component"
href="@threadlabs/looma/components/ui-calendar/ui-calendar.html"
>
<ui-calendar
value="2026-10-30"
today="2026-10-30"
locale="en-US"
label="Choose a date"
></ui-calendar><script setup>
import { UiCalendar } from "@threadlabs/looma";
</script>
<template>
<UiCalendar
value="2026-10-30"
today="2026-10-30"
locale="en-US"
label="Choose a date"
/>
</template>import { UiCalendar } from "@threadlabs/looma";
export default function Example() {
return <UiCalendar
value="2026-10-30"
today="2026-10-30"
locale="en-US"
label="Choose a date"
/>;
}/** @jsxImportSource preact */
import { UiCalendar } from "@threadlabs/looma";
export default function Example() {
return <UiCalendar
value="2026-10-30"
today="2026-10-30"
locale="en-US"
label="Choose a date"
/>;
}<script>
import { UiCalendar } from "@threadlabs/looma";
</script>
<UiCalendar
value="2026-10-30"
today="2026-10-30"
locale="en-US"
label="Choose a date"
/>import { Component } from "@angular/core";
import { UiCalendar } from "@threadlabs/looma";
@Component({
selector: "example-view",
standalone: true,
imports: [UiCalendar],
template: `
<section
ui-calendar
[value]="'2026-10-30'"
[today]="'2026-10-30'"
[locale]="'en-US'"
[label]="'Choose a date'"
></section>
`,
})
export default class Example {}Available weekdays
Weekends, a blocked interval and dates outside the inclusive bounds remain visible and unavailable. The same rules validate typed fields.
Su
M
T
W
Th
F
S
No available dates this month.
Code
<link
rel="component"
href="@threadlabs/looma/components/ui-calendar/ui-calendar.html"
>
<ui-calendar
month="2026-10"
min="2026-10-05"
max="2026-11-20"
disabled-weekdays="[6,7]"
disabled-ranges="[{"start":"2026-10-12","end":"2026-10-16"}]"
locale="en-US"
></ui-calendar><script setup>
import { UiCalendar } from "@threadlabs/looma";
</script>
<template>
<UiCalendar
month="2026-10"
min="2026-10-05"
max="2026-11-20"
:disabled-weekdays="[6, 7]"
:disabled-ranges="[{ start: '2026-10-12', end: '2026-10-16' }]"
locale="en-US"
/>
</template>import { UiCalendar } from "@threadlabs/looma";
export default function Example() {
return <UiCalendar
month="2026-10"
min="2026-10-05"
max="2026-11-20"
disabledWeekdays={[6,7]}
disabledRanges={[{"start":"2026-10-12","end":"2026-10-16"}]}
locale="en-US"
/>;
}/** @jsxImportSource preact */
import { UiCalendar } from "@threadlabs/looma";
export default function Example() {
return <UiCalendar
month="2026-10"
min="2026-10-05"
max="2026-11-20"
disabledWeekdays={[6,7]}
disabledRanges={[{"start":"2026-10-12","end":"2026-10-16"}]}
locale="en-US"
/>;
}<script>
import { UiCalendar } from "@threadlabs/looma";
</script>
<UiCalendar
month="2026-10"
min="2026-10-05"
max="2026-11-20"
disabledWeekdays={[6,7]}
disabledRanges={[{"start":"2026-10-12","end":"2026-10-16"}]}
locale="en-US"
/>import { Component } from "@angular/core";
import { UiCalendar } from "@threadlabs/looma";
@Component({
selector: "example-view",
standalone: true,
imports: [UiCalendar],
template: `
<section
ui-calendar
[month]="'2026-10'"
[min]="'2026-10-05'"
[max]="'2026-11-20'"
[disabledWeekdays]="[6, 7]"
[disabledRanges]="[{ start: '2026-10-12', end: '2026-10-16' }]"
[locale]="'en-US'"
></section>
`,
})
export default class Example {}Highlight a range
Calendar displays inclusive range endpoints; Date Range Picker coordinates independently editable endpoints.
Su
M
T
W
Th
F
S
No available dates this month.
Code
<link
rel="component"
href="@threadlabs/looma/components/ui-calendar/ui-calendar.html"
>
<ui-calendar
month="2026-10"
start="2026-10-12"
end="2026-10-17"
locale="en-US"
></ui-calendar><script setup>
import { UiCalendar } from "@threadlabs/looma";
</script>
<template>
<UiCalendar
month="2026-10"
start="2026-10-12"
end="2026-10-17"
locale="en-US"
/>
</template>import { UiCalendar } from "@threadlabs/looma";
export default function Example() {
return <UiCalendar
month="2026-10"
start="2026-10-12"
end="2026-10-17"
locale="en-US"
/>;
}/** @jsxImportSource preact */
import { UiCalendar } from "@threadlabs/looma";
export default function Example() {
return <UiCalendar
month="2026-10"
start="2026-10-12"
end="2026-10-17"
locale="en-US"
/>;
}<script>
import { UiCalendar } from "@threadlabs/looma";
</script>
<UiCalendar
month="2026-10"
start="2026-10-12"
end="2026-10-17"
locale="en-US"
/>import { Component } from "@angular/core";
import { UiCalendar } from "@threadlabs/looma";
@Component({
selector: "example-view",
standalone: true,
imports: [UiCalendar],
template: `
<section
ui-calendar
[month]="'2026-10'"
[start]="'2026-10-12'"
[end]="'2026-10-17'"
[locale]="'en-US'"
></section>
`,
})
export default class Example {}API
Package: @threadlabs/looma · Native root: section
Attributes
| Name | Description | Property | Type | Default | Allowed values |
|---|---|---|---|---|---|
allowed-dates | Allow-listed dates; omission is unrestricted, an explicit empty list allows none. | allowedDates | list(string) | — | — |
allowed-ranges | Inclusive allowed intervals, unioned with allowed-dates. | allowedRanges | list(object)
| — | — |
disabled | Prevents selection and navigation. | disabled | boolean | false | — |
disabled-dates | Unavailable dates, subtracted after bounds and allowed rules. | disabledDates | list(string) | [] | — |
disabled-ranges | Inclusive unavailable intervals with YYYY-MM-DD start and end dates, subtracted after bounds and allowed rules. | disabledRanges | list(object)
| [] | — |
disabled-weekdays | Unavailable ISO weekdays: Monday 1 through Sunday 7. | disabledWeekdays | list(integer) | [] | — |
empty-label | Message when the displayed month has no selectable date. | emptyLabel | string | No available dates this month. | — |
end | Optional range highlight's inclusive YYYY-MM-DD end. The caller owns range coordination. | end | string | | — |
label | Accessible name of the calendar group. | label | string | Calendar | — |
locale | Intl Gregorian labels, digits and default week order. | locale | string | en-US | — |
max | Inclusive latest selectable YYYY-MM-DD date. | max | string | | — |
min | Inclusive earliest selectable YYYY-MM-DD date. | min | string | | — |
model | Calendar data supplied by the component module's server-safe producer. Hosts prepare this input before SSR; caller-supplied fixtures override production. | model | object
| — | — |
month | Initial visible YYYY-MM, replaced on an external change. Omission follows value, today, then the current UTC month. | month | string | | — |
month-label | Accessible name of the month view toggle. | monthLabel | string | Choose month | — |
next-label | Accessible name of the next month, year or year-page action. | nextLabel | string | Next | — |
previous-label | Accessible name of the previous month, year or year-page action. | previousLabel | string | Previous | — |
readonly | Allows navigation while preventing selection. | readonly | boolean | false | — |
start | Optional range highlight's inclusive YYYY-MM-DD start. | start | string | | — |
today | Optional explicit YYYY-MM-DD date to mark as today; omission adds no today marker. | today | string | | — |
value | Initial selected YYYY-MM-DD civil date, replaced on an external change. Selection events always export just the date, without a time or timezone. Navigation does not select. | value | string | | — |
week-starts-on | Week 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. | weekStartsOn | integer | — | — |
year-error-label | Direct year entry error. | yearErrorLabel | string | Enter a year from 1 to 9999. | — |
year-label | Accessible name of the year view toggle and direct year input. | yearLabel | string | Choose year | — |
Framework props
| Name | Type | Default | Allowed values |
|---|---|---|---|
allowedDates | readonly (string)[] | — | — |
allowedRanges | readonly ({ readonly start: string; readonly end: string })[]
| — | — |
disabled | boolean | false | — |
disabledDates | readonly (string)[] | [] | — |
disabledRanges | readonly ({ readonly start: string; readonly end: string })[]
| [] | — |
disabledWeekdays | readonly (number)[] | [] | — |
emptyLabel | string | No available dates this month. | — |
end | string | | — |
label | string | Calendar | — |
locale | string | en-US | — |
max | string | | — |
min | string | | — |
model | { readonly rangeBands: readonly ({ readonly start: number; readonly end: number })[]; readonly month: string; readonly title: string; readonly monthLabel: string; readonly yearLabel: string; readonly weekStartsOn: number; readonly weekendColumns: readonly (number)[]; readonly weekdays: readonly ({ readonly day: number; readonly label: string; readonly fullLabel: string })[]; readonly rows: readonly (readonly ({ readonly value: string; readonly day: number; readonly outside: boolean; readonly label: string; readonly disabled: boolean; readonly selected: boolean; readonly today: boolean; readonly rangeStart: boolean; readonly rangeEnd: boolean; readonly inRange: boolean; readonly tabIndex: number })[])[]; readonly focusDate: string; readonly empty: boolean; readonly previousMonth: string; readonly nextMonth: string; readonly months: readonly ({ readonly value: string; readonly label: string; readonly fullLabel: string; readonly current: boolean; readonly outsideBounds: boolean; readonly disabled: boolean; readonly tabIndex: number })[]; readonly years: readonly ({ readonly value: number; readonly label: string; readonly current: boolean; readonly outsideBounds: boolean; readonly disabled: boolean; readonly tabIndex: number })[]; readonly yearPageStart: number; readonly yearPageLabel: string; readonly monthRows: readonly (readonly ({ readonly value: string; readonly label: string; readonly fullLabel: string; readonly current: boolean; readonly outsideBounds: boolean; readonly disabled: boolean; readonly tabIndex: number })[])[]; readonly yearRows: readonly (readonly ({ readonly value: number; readonly label: string; readonly current: boolean; readonly outsideBounds: boolean; readonly disabled: boolean; readonly tabIndex: number })[])[] }
| — | — |
month | string | | — |
monthLabel | string | Choose month | — |
nextLabel | string | Next | — |
previousLabel | string | Previous | — |
readonly | boolean | false | — |
start | string | | — |
today | string | | — |
value | string | | — |
weekStartsOn | number | — | — |
yearErrorLabel | string | Enter a year from 1 to 9999. | — |
yearLabel | string | Choose year | — |
Events
| Name | Detail | Description |
|---|---|---|
change | object
| Emitted when a toggleable control changes checked state. |
input | object
| Emitted with the declared detail payload. |
month-change | object
| Emitted with the declared detail payload. |
select | object
| Emitted when a selectable option becomes active. |
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.