Resource view
A time grid with a column per resource, and availability shading.
A time grid with one column per resource, such as rooms or people, with the time outside each resource's availability shaded.
Loading the preview…
import { timeGridView } from '@calendar-tsx/core';
timeGridView({ days: 1, groupBy: 'resource' });Day grids (dayGridView({ days: 1, groupBy: 'resource', maxEventsPerDay: 3 }), see
grouping), lists (listView({ weeks: 1, groupBy: 'resource' }), see
resource grouping) and timelines group by resource too.
Pass the resources to the calendar, in the order their columns should appear:
export const rooms: Calendar_Resource<Room>[] = [
{
id: 'room-a',
title: 'Room A',
availability: [{ start: at('2026-03-11T09:00'), end: at('2026-03-11T17:00') }],
data: { capacity: 8 },
},
{
id: 'room-b',
title: 'Room B',
availability: [],
data: { capacity: 4 },
},
];| Resource field | Description |
|---|---|
id | Matched against events' resourceIds. |
parentId | Optional parent resource ID. Every parent must be included. |
title | For your headers. |
availability | Absolute intervals the resource is available; the gaps are shaded. |
data | Your payload, typed as TResourceData. |
An event appears in every column whose resource ID is in its resourceIds; events without resourceIds appear in no
resource column. With more than one day, groupOrder: 'resource-first' (the default) keeps each resource's days
together so all-day bars can span them, and 'date-first' groups by day and splits all-day bars per column.
Resources with parentId form a hierarchy of any depth. Parents appear before descendants; roots and siblings
retain their input order. Children may precede their parents in the input. IDs must be unique; missing parents,
self-parenting and cycles throw. Replace the resource array when changing the hierarchy.
Time grids, day grids and resource agendas use the full depth-first order. Agendas continue to omit empty groups. Timeline supports expanding and collapsing descendants. A parent is an ordinary resource with its own events and availability. Assignments, availability and backgrounds do not inherit through the hierarchy.
Example
useLayout narrows the layout for <Show>; see narrowing the layout.
export const Rooms = () => {
const grid = useLayout('timeGrid');
return (
<Show when={grid()}>
{grid => (
<TimeGridView model={grid()}>
<TimeGridViewHeader>
<For each={grid().columns}>
{column => (
<TimeGridViewColumnHeader column={column}>
{column.resource?.title}
{column.isUnavailable && ' (closed)'}
</TimeGridViewColumnHeader>
)}
</For>
</TimeGridViewHeader>
<TimeGridViewBody model={grid()}>
<For each={grid().columns}>
{column => (
<TimeGridViewColumn column={column}>
<For each={column.unavailable}>{segment => <TimeGridViewUnavailable segment={segment} />}</For>
<For each={column.segments}>
{segment => <TimeGridViewEvent segment={segment}>{segment.event.data.title}</TimeGridViewEvent>}
</For>
</TimeGridViewColumn>
)}
</For>
</TimeGridViewBody>
</TimeGridView>
)}
</Show>
);
};Model
Resource columns are time-grid columns with three more fields:
| Column field | Description |
|---|---|
resource | The column's resource. |
unavailable | { key, start, span } segments between availability intervals, as fractions. |
isUnavailable | The resource has no availability on this day; the whole day is shaded. |
Parts
The time-grid parts, plus TimeGridViewUnavailable, which takes an unavailable segment,
renders an aria-hidden div and shades its span. TimeGridViewColumnHeader adds data-resource-id.