Availability timeline
A reusable Teams-style day grid: attendee rows, their busy blocks, and a drag-to-select/resize/move time slot picker. It owns grid layout, day navigation, drag mechanics, and the "everyone free" window math, every attendee row, busy block, suggested-slot button, legend, and empty/error state is entirely yours via templates, same content-agnostic split as bk-schedule-calendar.
Preview
A working preview of Availability timeline in the Brickclay style. Try it.
Playground
Exactly the config add-coaching-session uses, Coach/Employee/Participant rows behind a role rail labeled COACH/COACHEE/PART, drag to select a slot, resize/move the ghost, suggested "everyone free" windows underneath. No templates at all here, every visual is this component's own built-in default.
Available windows (everyone free)
Custom templates
Same component, a completely different domain: three conference rooms instead of people, no role grouping, and every visual slot templated, laneCellTemplate shows room + capacity instead of name + Available/Unavailable, busyChipTemplate shows the meeting subject and dims Tentative bookings, suggestedSlotTemplate restyles the quick-pick buttons, and headerActionsTemplate adds a "+ New meeting" button next to the day-nav controls.
+ New meeting clicked: 0 · Last slotSelected:, drag or click an empty span
API reference
Inputs
| Name | Type | Default | Note |
|---|---|---|---|
enabled | boolean | false | false shows emptyTitle/emptyMessage (or emptyStateTemplate) instead of the grid, e.g. before a coach/room is picked. |
data | AvailabilityTimelineData<T> | null | null | { people, busyBlocks, freeSlots, unresolvedPeople }. AvailabilityPerson<T>.data is a fully opaque, consumer-owned payload. |
loading / errorMessage | boolean / string | null | false / null | loading shows the built-in overlay while people is still empty; errorMessage shows the built-in banner (or errorStateTemplate) once it isn't. |
durationMinutes / selectedDate | number / Date | string | null | 30 / null | Drives the selection ghost's width/position and the click-to-select duration. Rebind selectedDate from slotSelected for the ghost to persist (controlled, same pattern as bk-schedule-calendar's view). |
disabled | boolean | false | Read-only: no click-to-select, no drag/resize/move. |
groupBy / showGroupRail / groupLabelFn / groupTitleFn | 'none' | 'role' | 'role' / true / none / none | 'role' groups consecutive rows sharing person.role behind a vertical rail label. Falls back to defaultAvailabilityGroupLabel/Title when the fn inputs are omitted. |
gridStartHour / gridHours | number | 0 / 24 | First hour shown and how many hours the grid spans, independent of businessWindow. |
businessWindow | { startHour, endHour } | { 8, 20 } | Window scanned for "everyone free" suggested slots, recomputed locally from busyBlocks whenever durationMinutes changes. |
slotSnapMinutes | number | 15 | Minute granularity click/drag/resize/move snap to. |
disallowPast | boolean | false | add-coaching-session uses [disallowPast]="true": Previous day stops at today, an overlay covers the already-past part of today, and click/drag/resize/move/suggested-slot selection can't start before now. Editing a session whose own date is already past still shows that day via selectedDate, this only blocks picking a new past time. |
| hourWidthPx / rowHeightPx / roleRailWidthPx / peopleRailWidthPx | number | 72 / 58 / 22 / 200 | Grid sizing knobs. |
laneCellTemplate | TemplateRef<AvailabilityLaneCellContext<T>> | none | Replaces the sticky attendee cell's built-in name + Available/Unavailable content. Context: { person, state, stateLabel, unresolved, unresolvedReason, conflict, placeholder }. |
busyChipTemplate | TemplateRef<AvailabilityBusyChipContext<T>> | none | Replaces a positioned busy block's built-in plain colored bar. The timeline still owns position/width/click-swallowing. Context: { person, block, conflictsSelection }. |
suggestedSlotTemplate | TemplateRef<AvailabilitySuggestedSlotContext> | none | Replaces an "everyone free" quick-pick button. Context: { slot, label, disabled, select() }. |
| legendTemplate / emptyStateTemplate / errorStateTemplate / headerActionsTemplate | TemplateRef<void | AvailabilityErrorStateContext> | none | Replace the Busy/Selected/Conflict legend, the empty state, the error banner, and add extra content next to the day-nav controls, respectively. |
placeholderLanes | { key, role }[] | [{ key: 'placeholder-1', role: 'Attendee' }] | Skeleton rows shown while loading and people is still empty. |
Outputs
| Name | Payload | Note |
|---|---|---|
slotSelected | { start: Date; end: Date } | A click, or a completed drag/resize/move, on an available span. Rebind selectedDate from this, a resize/move's own span keeps showing on the ghost until the next click/drag, independent of durationMinutes. |
dayChanged | Date | Prev/Today/Next in the built-in day-nav header. |