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
export const Rooms = () => {
const grid = useCalendarSelector((state: State) => state.layout);
if (grid.kind !== 'timeGrid') return null;
return (
<TimeGridView model={grid}>
<TimeGridViewHeader>
{grid.columns.map(column => (
<TimeGridViewColumnHeader key={column.key} column={column}>
{column.resource?.title}
{column.isUnavailable && ' (closed)'}
</TimeGridViewColumnHeader>
))}
</TimeGridViewHeader>
<TimeGridViewBody model={grid}>
{grid.columns.map(column => (
<TimeGridViewColumn key={column.key} column={column}>
{column.unavailable.map(segment => (
<TimeGridViewUnavailable key={segment.key} segment={segment} />
))}
{column.segments.map(segment => (
<TimeGridViewEvent key={segment.key} segment={segment}>
{segment.event.data.title}
</TimeGridViewEvent>
))}
</TimeGridViewColumn>
))}
</TimeGridViewBody>
</TimeGridView>
);
};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.