Skip to content

Resource Calendar

A powerful calendar component for visualizing and managing events across multiple resources like rooms, equipment, or team members.

The Resource Calendar extends the standard calendar with resource-based event organization. Events are displayed in horizontal rows where each row represents a resource (person, room, equipment, etc.). It supports all standard calendar features including drag-and-drop, recurring events, and internationalization.

import { IlamyResourceCalendar } from '@ilamy/calendar';
import type { Resource, CalendarEvent } from '@ilamy/calendar';
import dayjs from 'dayjs';
const resources: Resource[] = [
{
id: 'room-a',
title: 'Conference Room A',
color: '#3B82F6',
backgroundColor: '#EFF6FF',
},
{
id: 'room-b',
title: 'Conference Room B',
color: '#EF4444',
backgroundColor: '#FEF2F2',
},
];
const events: CalendarEvent[] = [
{
id: 'event-1',
title: 'Team Meeting',
start: dayjs('2025-08-04T09:00:00.000Z'),
end: dayjs('2025-08-04T10:00:00.000Z'),
uid: 'event-1@ilamy.calendar',
resourceId: 'room-a', // Assigned to Room A
},
];
function App() {
return (
<IlamyResourceCalendar
resources={resources}
events={events}
firstDayOfWeek="sunday"
initialView="week"
timeFormat="12-hour"
/>
);
}

Resources represent the entities across which events are organized.

interface Resource {
// Unique identifier for the resource
id: string | number;
// Display title of the resource
title: string;
// Color for resource text (hex, rgb, or CSS class)
color?: string;
// Background color for resource (hex, rgb, or CSS class)
backgroundColor?: string;
// Optional position for resource display order
position?: number;
}
Colorful Resources
const resources: Resource[] = [
{
id: 'designer',
title: 'Design Team',
color: '#8B5CF6', // Purple text
backgroundColor: '#F5F3FF', // Light purple background
},
{
id: 'engineer',
title: 'Engineering Team',
color: '#10B981', // Green text
backgroundColor: '#ECFDF5', // Light green background
},
];

The standard CalendarEvent interface includes optional resource assignment fields for use with resource calendars.

interface CalendarEvent {
// ... standard event properties (id, title, start, end, etc.)
// Single resource assignment
resourceId?: string | number;
// Multiple resource assignment (cross-resource events)
resourceIds?: (string | number)[];
}
Event Assigned to One Resource
const event: CalendarEvent = {
id: 'meeting-1',
title: 'Team Standup',
start: dayjs('2025-08-04T10:00:00.000Z'),
end: dayjs('2025-08-04T10:30:00.000Z'),
uid: 'meeting-1@ilamy.calendar',
resourceId: 'room-a', // Assigned to one resource
};

Events that span multiple resources using the resourceIds array:

Event Spanning Multiple Resources
const event: CalendarEvent = {
id: 'all-hands',
title: 'All Hands Meeting',
start: dayjs('2025-08-04T14:00:00.000Z'),
end: dayjs('2025-08-04T15:00:00.000Z'),
uid: 'all-hands@ilamy.calendar',
resourceIds: ['room-a', 'room-b', 'room-c'], // Spans multiple resources
color: '#8B5CF6',
};

The IlamyResourceCalendar component extends all props from IlamyCalendar (including locale, timezone, timeFormat, etc.) with resource-specific additions below.

PropTypeDefaultDescription
resourcesResource[][]Array of resources to display
eventsCalendarEvent[][]Array of events with resource assignments (using resourceId or resourceIds properties)
renderResource(resource: Resource) => ReactNode-Custom function to render resource headers
Conference Room Booking
import { IlamyResourceCalendar } from '@ilamy/calendar';
import type { CalendarEvent, CellClickInfo } from '@ilamy/calendar';
import { useState } from 'react';
import dayjs from 'dayjs';
const RoomBookingCalendar = () => {
const [events, setEvents] = useState<CalendarEvent[]>([]);
const rooms: Resource[] = [
{
id: 'conf-a',
title: 'Conference Room A (10 people)',
color: '#3B82F6',
backgroundColor: '#EFF6FF',
},
{
id: 'conf-b',
title: 'Conference Room B (20 people)',
color: '#EF4444',
backgroundColor: '#FEF2F2',
},
{
id: 'board-room',
title: 'Board Room (8 people)',
color: '#8B5CF6',
backgroundColor: '#F5F3FF',
},
];
const handleCellClick = (info: CellClickInfo) => {
const { start, end, resourceId } = info;
if (!resourceId) return;
const newEvent: CalendarEvent = {
id: `booking-${Date.now()}`,
title: 'New Booking',
start,
end,
uid: `booking-${Date.now()}@company.com`,
resourceId,
color: '#10B981',
};
setEvents((prev) => [...prev, newEvent]);
};
const handleEventUpdate = (event: CalendarEvent) => {
setEvents((prev) =>
prev.map((e) => (e.id === event.id ? event : e))
);
};
return (
<IlamyResourceCalendar
resources={rooms}
events={events}
initialView="week"
onCellClick={handleCellClick}
onEventUpdate={handleEventUpdate}
firstDayOfWeek="monday"
/>
);
};

Customize how resources are displayed using the renderResource prop:

Custom Resource Headers with Icons
import { Calendar, MapPin, Users } from 'lucide-react';
const IconResourceRenderer = (resource: Resource) => {
const getResourceIcon = (resourceId: string) => {
if (resourceId.includes('room')) return <MapPin className="h-4 w-4" />;
if (resourceId.includes('team')) return <Users className="h-4 w-4" />;
return <Calendar className="h-4 w-4" />;
};
return (
<div className="flex items-center gap-2 p-2">
<div style={{ color: resource.color }}>
{getResourceIcon(resource.id)}
</div>
<div className="flex flex-col">
<span className="font-medium">{resource.title}</span>
<span className="text-xs" style={{ color: resource.color }}>
Available
</span>
</div>
</div>
);
};
function App() {
return (
<IlamyResourceCalendar
resources={resources}
events={events}
renderResource={IconResourceRenderer}
/>
);
}

The Resource Calendar supports three views, each displaying resources in horizontal rows.

Timeline view with resources as rows and days as columns. Compact event display with scroll for all resources.

initialView="month"

Detailed 7-day timeline with hourly time slots. Perfect for precise scheduling with drag-and-drop between resources.

initialView="week"

Focused single-day view with maximum detail. Full hourly breakdown across all resources.

initialView="day"
  • Use meaningful resource IDs (e.g., ‘room-a’, ‘john-doe’)
  • Set position property to control display order
  • Group related resources by type
  • Include capacity info in resource titles when relevant
  • Use resourceId for single resource events (simpler and more performant)
  • Use resourceIds array only when event truly spans multiple resources
  • Validate resource IDs exist in resources array
  • Handle conflicts and validate resource availability before booking
  • Memoize event filtering for large datasets
  • Consider virtualization for 50+ resources
  • Batch multiple state updates together
  • Use React.memo for custom resource renderers