Resource Calendar

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

Overview

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.

Try it out: Visit the interactive demo and toggle to "Resource Calendar" mode to see it in action!

Basic Usage

import { IlamyResourceCalendar } from '@ilamy/calendar';
import type { Resource, ResourceCalendarEvent } 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: ResourceCalendarEvent[] = [
  {
    id: 'event-1',
    title: 'Team Meeting',
    start: dayjs('2025-08-04T09:00:00.000Z'),
    end: dayjs('2025-08-04T10:00:00.000Z'),
    uid: '[email protected]',
    resourceId: 'room-a', // Assigned to Room A
  },
];

function App() {
  return (
    <IlamyResourceCalendar
      resources={resources}
      events={events}
      firstDayOfWeek="sunday"
      initialView="week"
    />
  );
}

Note: For sticky headers to work properly, the calendar's container must have a fixed height (e.g., height: 600px).

Resource Interface

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;
}

Resource Color System

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
  },
];

Resource Calendar Events

Resource calendar events extend the standard CalendarEvent interface with resource assignment fields.

interface ResourceCalendarEvent extends CalendarEvent {
  // Single resource assignment
  resourceId?: string | number;

  // Multiple resource assignment (cross-resource events)
  resourceIds?: (string | number)[];
}

Single Resource Events

const event: ResourceCalendarEvent = {
  id: 'meeting-1',
  title: 'Team Standup',
  start: dayjs('2025-08-04T10:00:00.000Z'),
  end: dayjs('2025-08-04T10:30:00.000Z'),
  uid: '[email protected]',
  resourceId: 'room-a', // Assigned to one resource
};

Cross-Resource Events

Events that span multiple resources using the resourceIds array:

const event: ResourceCalendarEvent = {
  id: 'all-hands',
  title: 'All Hands Meeting',
  start: dayjs('2025-08-04T14:00:00.000Z'),
  end: dayjs('2025-08-04T15:00:00.000Z'),
  uid: '[email protected]',
  resourceIds: ['room-a', 'room-b', 'room-c'], // Spans multiple resources
  color: '#8B5CF6',
};

Props

The IlamyResourceCalendar component extends all props from IlamyCalendar with resource-specific additions.

Resource-Specific Props

NameTypeDefaultDescription
resources
Resource[][]

Array of resources to display

events
ResourceCalendarEvent[][]

Array of events with resource assignments

renderResource
(resource: Resource) => ReactNode

Custom function to render resource headers

Examples

Room Booking System

import { IlamyResourceCalendar } from '@ilamy/calendar';
import { useState } from 'react';
import dayjs from 'dayjs';

const RoomBookingCalendar = () => {
  const [events, setEvents] = useState<ResourceCalendarEvent[]>([]);

  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 = (
    start: dayjs.Dayjs,
    end: dayjs.Dayjs,
    resourceId?: string | number
  ) => {
    if (!resourceId) return;

    const newEvent: ResourceCalendarEvent = {
      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: ResourceCalendarEvent) => {
    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"
    />
  );
};

Custom Resource Rendering

Customize how resources are displayed using the renderResource prop:

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}
    />
  );
}

Views

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

Month View

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

initialView="month"

Week View

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

initialView="week"

Day View

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

initialView="day"

🚧 Coming Soon: Custom Duration Views

Custom duration views (e.g., 3-day, 2-week, 4-week views) for the resource calendar are currently in development and will be available in a future release. Stay tuned for updates!

Best Practices

Resource Organization

  • ✓ 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

Event Assignment

  • ✓ 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

Performance

  • ✓ Memoize event filtering for large datasets
  • ✓ Consider virtualization for 50+ resources
  • ✓ Batch multiple state updates together
  • ✓ Use React.memo for custom resource renderers