Skip to content

Scheduler ​

Month-view scheduling component: renders event chips (title + color bar) inside day cells; events read/write channel plus addEvent / updateEvent / removeEvent CRUD methods; clicking a chip dispatches oas-event-click, clicking a day dispatches oas-day-click (host attaches an editor), and data changes made through the CRUD methods dispatch oas-events-change (writing via setAttribute('events', …) does not).

Basic Usage ​

Week start & locale (first-day-of-week + locale)

Month view + event chips (title / color bar / +N collapse)

Week / Day Views ​

Week view (time axis + timed event blocks; all-day row on top)

Day view (single-column time axis) + oas-view-change

Week/day views show a time axis (start-hour / end-hour, default 8–20): events with start/end are positioned as blocks by time; untimed events go to the all-day row on top; switching views via the header buttons dispatches oas-view-change. Event blocks support drag-to-move (drop on a target column/time to change date + start, keeping duration) and bottom-edge drag-resize (change end in 15-minute steps), written back with oas-events-change on settle.

Recurrence & Reminders ​

Recurrence rules (RRULE subset: daily/weekly/monthly + interval + until)

repeat expands occurrences from date by freq × interval (daily by day interval, weekly by week, monthly by same day-of-month), with until as the inclusive end; el.events still reads the raw entries (expansion happens only at render time).

Reminders (remind minutes; oas-remind when due)

For events with remind (minutes), the component dispatches oas-remind (detail: { id, event }) at start − remind minutes (untimed events count as 00:00). Past/removed/disconnected events never fire.

Timezone & Agenda View ​

Agenda view (28-day chronological list from anchor)

view="agenda" lists events grouped by day for 28 days from the anchor (recurring events expanded): timed events show start–end, untimed events are labeled all-day; clicking a row dispatches oas-event-click, clicking a day header dispatches oas-day-click.

Timezone (affects title/column headers and the today marker)

timezone accepts an IANA name (e.g. Asia/Shanghai / America/New_York / UTC) and affects date formatting in the title/column headers and the today marker (via Intl timeZone); invalid values fall back to local.

Resource Views & Drag-to-Create ​

Single-day resource view (view=resource: rows = resources, horizontal = hours)

Week x resource matrix (view=resource-week)

Drag to create (drag a range on an empty time cell → oas-create)

RTL (dir=rtl: resource timeline and resource column mirror)

view="resource" renders a single-day schedule with resources as rows and hours across; view="resource-week" is a week x resource matrix (rows = resources, columns = 7 days of the week). Events are assigned to a resource row via their resource field; absent or unknown ids go to the "Unassigned" row. Dragging a range (>=15 minutes) on an empty time cell dispatches oas-create (detail: { date, start, end, resource? }) — the component does not create the event; the host calls addEvent. A shorter drag is treated as a click and dispatches oas-day-click. show-now (on by default) renders a now line at the current time.

CRUD (method channel) ​

addEvent / updateEvent / removeEvent + oas-events-change feedback

Add "Review"Rename firstRemove first

Click Feedback (host integration) ​

oas-event-click / oas-day-click host integration

Clicking an event chip dispatches oas-event-click (detail: { id, event }, without triggering the day click); clicking an empty day cell dispatches oas-day-click (detail: { date }) — the host opens an editor/form there; the component ships no built-in edit form.

Large datasets (virtualization) ​

In the resource view the resource rows, and in the day view the hour axis, render for the visible window only: the number of rendered rows/ticks does not grow with the dataset size, and spacers preserve the scroll range (total height invariant). After a scroll rebuild focus is restored by event id, and window rebuilds are suppressed while a drag/create gesture is active (so pointer capture is not destroyed). The resource view is capped by --oas-scheduler-resource-max-height (default 640px, matching the timeline); beyond that it scrolls internally and virtualizes. Resource rows and the timeline carry aria-rowcount and absolute aria-rowindex.

Server-side resource row window (windowed) and printing ​

The resource views (resource / resource-week) support server-side slices: windowed + total + window-start, with resources carrying only [window-start, window-start + resources.length). The component emits oas-window-request (absolute, half-open row range) when the visible window is not covered; the host responds with a new slice and updates window-start. aria-rowcount uses total, and aria-rowindex uses absolute row numbers.

  • In windowed mode the component does not append an "Unassigned" row automatically; the host can provide the reserved id __unassigned__, and events with no/unknown resource are grouped there.
  • Repeat events inside the loaded slice are still expanded locally; when the host expands occurrences it must strip repeat from the base event (or stop sending the base series), otherwise the same day renders twice. Give each occurrence a unique id.
  • Print CSS (@media print) hides the toolbar/view buttons and removes scroll caps (including agenda); beforeprint temporarily disables row/hour virtualization and prints the loaded slice (windowed omits spacer blank pages), and afterprint restores window rendering.
html
<oas-scheduler
  view="resource"
  windowed
  total="500"
  window-start="100"
  resources='[{"id":"r100","title":"Resource 100"}]'
  events='[{"date":"2026-08-10","title":"Standup","start":"09:00","end":"09:30","resource":"r100"}]'
></oas-scheduler>

ICS Export ​

ts
import { eventsToIcs } from '@oas-ui/ui'

const ics = el.exportIcs() // current events
const standalone = eventsToIcs(events, { calendarName: 'My Calendar' })
  • Events without start export as all-day events (DTSTART/DTEND;VALUE=DATE, end = next day); timed events use floating local time (no TZID).
  • repeat maps to RRULE:FREQ=...;INTERVAL=...;UNTIL=... (until is inclusive).
  • Text is RFC 5545 escaped; output uses CRLF and 75-byte folding; invalid-date events are skipped. The now option fixes DTSTAMP for reproducible exports/tests.

API ​

oas-scheduler ​

Attributes ​

AttributeDescriptionTypeDefault
end-hourTime axis end hour (> start-hour and <= 24, default 20)string20
eventsSchedule events (JSON): [{ id?, date: YYYY-MM-DD, title, color?, start?, end? }] — chips rendered in day cells (title + color bar), collapsed to +N beyond 2SchedulerEvent[][]
first-day-of-weekFirst day of week (0-6); defaults to locale-derivedstring—
localeLocalization (overrides config-provider injection and global locale)string—
page-show-datePanel month anchor (controlled): yyyy-MM-dd; re-anchors the shown month on changestring—
resourcesResources (JSON): [{ id, title, color? }] — resource views group by resource; events whose resource is absent or unknown go to the 'Unassigned' rowSchedulerResource[][]
show-nowCurrent-time line (on by default; false disables): renders a now line for today in week/day and single-day resource viewsstringtrue
start-hourTime axis start hour (0-23, default 8)string8
timezoneTimezone (IANA, e.g. Asia/Shanghai; empty = local): affects title/column date formatting and the today marker (via Intl timeZone); invalid values fall back to localstring—
totalTotal resource row count in windowed mode (must be positive); used for aria-rowcount and absolute row indices.string—
viewView: month (default) / week / day / agenda / resource / resource-week; week/day views show a time axis with positioned event blocks (untimed events go to the all-day row); agenda shows a 28-day chronological list; resource is a single-day horizontal resource timeline, resource-week a week x resource matrixSchedulerViewmonth
window-startAbsolute row index of the first loaded row in windowed mode.string0
windowedServer-side resource row window mode (boolean, off by default): for resource / resource-week, resources carries only the [window-start, window-start + resources.length) slice; emits oas-window-request (absolute, half-open range) when the visible window is uncovered. The component does not auto-append an Unassigned row; the host may provide the reserved id __unassigned__.boolean—

Property (JS property; see each row for attribute reflection) ​

PropertyDescriptionTypeDefault
eventsSchedule events (SchedulerEvent[]): el.events reads (copy incl. auto ids); el.events = [...] writes (syncs the events attribute + re-renders + dispatches oas-events-change)SchedulerEvent[][]
resourcesResources (SchedulerResource[]): el.resources reads (copy); el.resources = [...] writes (syncs the resources attribute + re-renders)SchedulerResource[][]

Events ​

EventDescription
oas-createDispatched when an empty time cell is dragged out to a range of >=15 minutes, detail: { date, start, end, resource? } — the component does not create the event; the host calls addEvent. A shorter drag is treated as oas-day-click
oas-day-clickDispatched when an empty day cell is clicked, detail: { date, resource? } (resource row id in resource views) — host attaches an add form
oas-event-clickDispatched when an event chip is clicked, detail: { id, event } (does not trigger the day click)
oas-events-changeDispatched on any events change (set/addEvent/updateEvent/removeEvent), detail:
oas-remindDispatched when an event reminder is due, detail: { id, event } (fires at start - remind minutes via built-in timers)
oas-view-changeDispatched on view switch (month/week/day/agenda), detail: { view }; not dispatched on initial attribute absorption
oas-window-requestEmitted in windowed mode when the visible resource-row window is not covered by the loaded slice; detail: { start, end, reason } (absolute, half-open; the same window is not emitted twice).

CSS Variables ​

CSS VariableDefault
--oas-scheduler-resource-max-height640px

Released under the MIT OR Apache-2.0 License.