English
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
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/unknownresourceare grouped there. - Repeat events inside the loaded slice are still expanded locally; when the host expands occurrences it must strip
repeatfrom 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);beforeprinttemporarily disables row/hour virtualization and prints the loaded slice (windowed omits spacer blank pages), andafterprintrestores 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
startexport as all-day events (DTSTART/DTEND;VALUE=DATE, end = next day); timed events use floating local time (no TZID). repeatmaps toRRULE:FREQ=...;INTERVAL=...;UNTIL=...(untilis inclusive).- Text is RFC 5545 escaped; output uses CRLF and 75-byte folding; invalid-date events are skipped. The
nowoption fixesDTSTAMPfor reproducible exports/tests.
API
oas-scheduler
Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
end-hour | Time axis end hour (> start-hour and <= 24, default 20) | string | 20 |
events | Schedule events (JSON): [{ id?, date: YYYY-MM-DD, title, color?, start?, end? }] — chips rendered in day cells (title + color bar), collapsed to +N beyond 2 | SchedulerEvent[] | [] |
first-day-of-week | First day of week (0-6); defaults to locale-derived | string | — |
locale | Localization (overrides config-provider injection and global locale) | string | — |
page-show-date | Panel month anchor (controlled): yyyy-MM-dd; re-anchors the shown month on change | string | — |
resources | Resources (JSON): [{ id, title, color? }] — resource views group by resource; events whose resource is absent or unknown go to the 'Unassigned' row | SchedulerResource[] | [] |
show-now | Current-time line (on by default; false disables): renders a now line for today in week/day and single-day resource views | string | true |
start-hour | Time axis start hour (0-23, default 8) | string | 8 |
timezone | Timezone (IANA, e.g. Asia/Shanghai; empty = local): affects title/column date formatting and the today marker (via Intl timeZone); invalid values fall back to local | string | — |
total | Total resource row count in windowed mode (must be positive); used for aria-rowcount and absolute row indices. | string | — |
view | View: 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 matrix | SchedulerView | month |
window-start | Absolute row index of the first loaded row in windowed mode. | string | 0 |
windowed | Server-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)
| Property | Description | Type | Default |
|---|---|---|---|
events | Schedule events (SchedulerEvent[]): el.events reads (copy incl. auto ids); el.events = [...] writes (syncs the events attribute + re-renders + dispatches oas-events-change) | SchedulerEvent[] | [] |
resources | Resources (SchedulerResource[]): el.resources reads (copy); el.resources = [...] writes (syncs the resources attribute + re-renders) | SchedulerResource[] | [] |
Events
| Event | Description |
|---|---|
oas-create | Dispatched 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-click | Dispatched when an empty day cell is clicked, detail: { date, resource? } (resource row id in resource views) — host attaches an add form |
oas-event-click | Dispatched when an event chip is clicked, detail: { id, event } (does not trigger the day click) |
oas-events-change | Dispatched on any events change (set/addEvent/updateEvent/removeEvent), detail: |
oas-remind | Dispatched when an event reminder is due, detail: { id, event } (fires at start - remind minutes via built-in timers) |
oas-view-change | Dispatched on view switch (month/week/day/agenda), detail: { view }; not dispatched on initial attribute absorption |
oas-window-request | Emitted 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 Variable | Default |
|---|---|
--oas-scheduler-resource-max-height | 640px |