Calendar
A comprehensive React calendar component with month, week, day, and year views, plus powerful event lifecycle callbacks.
Basic Usage
Section titled “Basic Usage”The Calendar component is the main component for displaying calendar views. It supports various props for customization and event handling. Events should follow the CalendarEvent interface.
import { IlamyCalendar } from '@ilamy/calendar';
const events = [ { id: '1', title: 'Team Meeting', start: new Date('2024-01-15T10:00:00'), end: new Date('2024-01-15T11:00:00'), description: 'Weekly team sync', backgroundColor: '#3b82f6' color: 'black' }, { id: '2', title: 'Project Deadline', start: new Date('2024-01-20T23:59:59'), end: new Date('2024-01-20T23:59:59'), allDay: true, backgroundColor: '#ef4444' color: 'black' }];
function MyCalendar() { return ( <IlamyCalendar events={events} /> );}Basic Props
Section titled “Basic Props”| Prop | Type | Default | Description |
|---|---|---|---|
events | CalendarEvent[] | [] | Array of events to display in the calendar |
initialView | 'month' | 'week' | 'day' | 'year' | 'month' | Sets the initial view when the calendar loads |
initialDate | dayjs.Dayjs | Date | string | undefined | undefined (today’s date) | Sets the initial date displayed when the calendar loads. When undefined, defaults to today’s date |
firstDayOfWeek | 'sunday' | 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday' | 'sunday' | The first day of the week to display |
dayMaxEvents | number | 4 | Maximum number of events to display in a day cell |
renderEvent | (event: CalendarEvent) => ReactNode | - | Custom function to render individual events |
locale | string | 'en' | Locale for date formatting (e.g., “en”, “fr”, “de”) |
timezone | string | Whatever your local timezone is | Timezone for date handling (e.g., “UTC”, “America/New_York”) |
timeFormat | '12-hour' | '24-hour' | '12-hour' | Time format for displaying times in week and day views (e.g., ‘1:00 PM’ vs ‘13:00’) |
stickyViewHeader | boolean | true | Whether to stick the view header to the top |
viewHeaderClassName | string | '' | Custom class name for the view header |
headerComponent | ReactNode | null | Custom header component to render above the calendar |
disableCellClick | boolean | false | Disable cell click interactions |
disableEventClick | boolean | false | Disable event click interactions |
disableDragAndDrop | boolean | false | Disable drag-and-drop functionality for events |
eventSpacing | number | 2 | Spacing (in pixels) between events in calendar views. Allows customizable gaps between events for better visual clarity. |
businessHours | BusinessHours | BusinessHours[] | undefined | Restrict calendar interactions to specified days and time ranges. Users can only create and edit events within business hours. Supports single object or array for different hours per day. |
renderEventForm | (props: EventFormProps) => ReactNode | undefined | Custom function to render the event form for creating and editing events. When provided, replaces the default event form. |
classesOverride | ClassesOverride | undefined | Custom class names to override default styling for various calendar elements, including disabled cells. |
translations | Translations | - | Translations object for internationalization. If both translations and translator are provided, translator takes priority. |
translator | TranslatorFunction | - | Translator function for internationalization. Takes priority over translations object if both are provided. |
Event Handlers
Section titled “Event Handlers”| Prop | Type | Description |
|---|---|---|
onEventClick | (event: CalendarEvent) => void | Called when an event is clicked |
onCellClick | (info: CellClickInfo) => void | Called when a date cell is clicked. Receives CellClickInfo object with start, end, and optional resourceId. |
onViewChange | (view: 'month' | 'week' | 'day' | 'year') => void | Called when the calendar view changes |
onEventAdd | (event: CalendarEvent) => void | Called when a new event is created |
onEventUpdate | (event: CalendarEvent) => void | Called when an existing event is updated |
onEventDelete | (event: CalendarEvent) => void | Called when an event is deleted |
onDateChange | (date: dayjs.Dayjs) => void | Called when the calendar date changes |
Examples
Section titled “Examples”With Event Handlers
Section titled “With Event Handlers”import { IlamyCalendar } from '@ilamy/calendar';
function MyCalendar() { const handleEventClick = (event) => { console.log('Event clicked:', event); // Open event details modal, navigate to event page, etc. };
const handleDateClick = (info) => { console.log('Date clicked:', info.start, info.end); // Create new event, switch to day view, etc. // info contains: { start: Dayjs, end: Dayjs, resourceId?: string | number } };
const handleViewChange = (view) => { console.log('View changed to:', view); // Update URL, track analytics, etc. };
return ( <IlamyCalendar events={events} firstDayOfWeek="monday" onEventClick={handleEventClick} onCellClick={handleDateClick} onViewChange={handleViewChange} /> );}Internationalization
Section titled “Internationalization”The calendar supports comprehensive internationalization including locale-based formatting, custom translations, and translator functions. For detailed documentation and examples, see the Internationalization guide.
Time Format Configuration
Section titled “Time Format Configuration”Configure whether times are displayed in 12-hour or 24-hour format in week and day views.
import { IlamyCalendar } from '@ilamy/calendar';
function MyCalendar() { return ( <> {/* 12-hour format (default): displays as "1:00 PM", "2:30 PM" */} <IlamyCalendar events={events} initialView="week" timeFormat="12-hour" />
{/* 24-hour format: displays as "13:00", "14:30" */} <IlamyCalendar events={events} initialView="week" timeFormat="24-hour" /> </> );}Custom Event Rendering
Section titled “Custom Event Rendering”import { IlamyCalendar } from '@ilamy/calendar';
function CustomCalendar() { const renderEvent = (event) => ( <div className="px-2 py-1 rounded bg-blue-100 text-blue-800"> <div className="font-semibold">{event.title}</div> <div className="text-xs">{event.description}</div> </div> );
return ( <IlamyCalendar events={events} renderEvent={renderEvent} onEventClick={(event) => alert(`Clicked: ${event.title}`)} onCellClick={(info) => console.log('Selected date:', info.start, info.end)} /> );}Initial View and Event Lifecycle
Section titled “Initial View and Event Lifecycle”import { IlamyCalendar } from '@ilamy/calendar';import { useState } from 'react';
function AdvancedCalendar() { const [events, setEvents] = useState([]);
const handleEventAdd = (event) => { console.log('New event added:', event); setEvents(prev => [...prev, event]); // Save to your backend API };
const handleEventUpdate = (updatedEvent) => { console.log('Event updated:', updatedEvent); setEvents(prev => prev.map(event => event.id === updatedEvent.id ? updatedEvent : event ) ); // Update in your backend API };
const handleEventDelete = (deletedEvent) => { console.log('Event deleted:', deletedEvent); setEvents(prev => prev.filter(event => event.id !== deletedEvent.id) ); // Delete from your backend API };
const handleDateChange = (date) => { console.log('Date changed to:', date.format('YYYY-MM-DD')); // Load events for the new date range // fetchEventsForDate(date); };
return ( <IlamyCalendar events={events} initialView="week" // Start with week view onEventAdd={handleEventAdd} onEventUpdate={handleEventUpdate} onEventDelete={handleEventDelete} onDateChange={handleDateChange} onEventClick={(event) => console.log('Event clicked:', event)} onCellClick={(info) => console.log('Cell clicked:', info.start, info.end)} /> );}View Options
Section titled “View Options”The calendar supports multiple view modes that you can set using the initialView prop.
Month View
Section titled “Month View”Traditional monthly calendar showing the entire month at a glance.
<IlamyCalendar initialView="month" events={events} />Week View
Section titled “Week View”Weekly view showing 7 days with detailed time slots.
<IlamyCalendar initialView="week" events={events} />Day View
Section titled “Day View”Single day view with hourly time slots for detailed scheduling.
<IlamyCalendar initialView="day" events={events} />Year View
Section titled “Year View”Annual overview showing all 12 months for long-term planning.
<IlamyCalendar initialView="year" events={events} />// Month view (default)<IlamyCalendar initialView="month" events={events} />
// Week view for detailed scheduling<IlamyCalendar initialView="week" events={events} />
// Day view for hourly planning<IlamyCalendar initialView="day" events={events} />
// Year view for long-term overview<IlamyCalendar initialView="year" events={events} />Business Hours
Section titled “Business Hours”Restrict calendar interactions to specific days and time ranges. When configured, users can only create and edit events within business hours. This is particularly useful for appointment booking, scheduling applications, and enforcing availability constraints.
import { IlamyCalendar } from '@ilamy/calendar';
function BusinessCalendar() { const events = [/* your events */];
return ( <IlamyCalendar events={events} businessHours={{ daysOfWeek: ['monday', 'tuesday', 'wednesday', 'thursday', 'friday'], startTime: 9, // 9 AM endTime: 17, // 5 PM }} /> );}daysOfWeek
Section titled “daysOfWeek”Array of day names that are considered business days. Users can only interact with the calendar on these days.
Type: string[]
Valid values: 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'
startTime
Section titled “startTime”Hour when business hours begin (24-hour format, inclusive). Events cannot be created or modified before this time.
Type: number (0-23)
endTime
Section titled “endTime”Hour when business hours end (24-hour format, exclusive). Events cannot be created or modified at or after this time.
Type: number (0-23)
Custom Event Form
Section titled “Custom Event Form”Replace the default event form with your own custom implementation using the renderEventForm prop. This gives you full control over the event creation and editing experience.
import { IlamyCalendar, EventFormProps, CalendarEvent } from '@ilamy/calendar';
const CustomEventForm = ({ open, selectedEvent, onAdd, onUpdate, onDelete, onClose,}: EventFormProps) => { if (!open) return null;
const handleSubmit = (formData: FormData) => { const eventData: CalendarEvent = { id: selectedEvent?.id || `event-${Date.now()}`, title: formData.get('title') as string, start: selectedEvent?.start || new Date(), end: selectedEvent?.end || new Date(), };
if (selectedEvent?.id) { onUpdate?.(eventData); } else { onAdd?.(eventData); } onClose(); };
return ( <dialog open={open} className="modal"> <form onSubmit={(e) => { e.preventDefault(); handleSubmit(new FormData(e.currentTarget)); }}> <input name="title" defaultValue={selectedEvent?.title} placeholder="Event title" /> <div className="actions"> {selectedEvent?.id && ( <button type="button" onClick={() => { onDelete?.(selectedEvent); onClose(); }}>Delete</button> )} <button type="button" onClick={onClose}>Cancel</button> <button type="submit"> {selectedEvent?.id ? 'Update' : 'Create'} </button> </div> </form> </dialog> );};
function MyCalendar() { return ( <IlamyCalendar events={events} renderEventForm={(props) => <CustomEventForm {...props} />} /> );}EventFormProps Properties
Section titled “EventFormProps Properties”open- Boolean indicating if the form should be visibleselectedEvent- The event being edited (null for new events)onAdd- Callback to create a new eventonUpdate- Callback to update an existing eventonDelete- Callback to delete an eventonClose- Callback to close the form (required)
Event Lifecycle Callbacks
Section titled “Event Lifecycle Callbacks”Handle event creation, updates, and deletion with powerful callback functions. These callbacks are essential for maintaining your event data and integrating with backend APIs.
Event Management Callbacks
Section titled “Event Management Callbacks”onEventAdd
Section titled “onEventAdd”Triggered when a user creates a new event through the calendar interface.
Type: (event: CalendarEvent) => void
onEventUpdate
Section titled “onEventUpdate”Called when an existing event is modified (e.g., dragged, resized, or edited).
Type: (event: CalendarEvent) => void
onEventDelete
Section titled “onEventDelete”Invoked when a user deletes an event from the calendar.
Type: (event: CalendarEvent) => void
onDateChange
Section titled “onDateChange”Fired when the user navigates to a different date or time period.
Type: (date: dayjs.Dayjs) => void
Complete Integration Example
Section titled “Complete Integration Example”import { IlamyCalendar } from '@ilamy/calendar';import { useState } from 'react';
function CalendarWithAPI() { const [events, setEvents] = useState([]); const [loading, setLoading] = useState(false);
// Handle new event creation const handleEventAdd = async (event) => { setLoading(true); try { // Save to backend const response = await fetch('/api/events', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(event) });
if (response.ok) { const savedEvent = await response.json(); setEvents(prev => [...prev, savedEvent]); console.log('Event created successfully:', savedEvent); } } catch (error) { console.error('Failed to create event:', error); } finally { setLoading(false); } };
// Handle event updates const handleEventUpdate = async (updatedEvent) => { setLoading(true); try { const response = await fetch('/api/events/' + updatedEvent.id, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(updatedEvent) });
if (response.ok) { setEvents(prev => prev.map(event => event.id === updatedEvent.id ? updatedEvent : event ) ); console.log('Event updated successfully:', updatedEvent); } } catch (error) { console.error('Failed to update event:', error); } finally { setLoading(false); } };
// Handle event deletion const handleEventDelete = async (deletedEvent) => { setLoading(true); try { const response = await fetch('/api/events/' + deletedEvent.id, { method: 'DELETE' });
if (response.ok) { setEvents(prev => prev.filter(event => event.id !== deletedEvent.id) ); console.log('Event deleted successfully:', deletedEvent); } } catch (error) { console.error('Failed to delete event:', error); } finally { setLoading(false); } };
// Handle date navigation const handleDateChange = async (date) => { console.log('Navigating to:', date.format('YYYY-MM-DD'));
// Optionally load events for the new date range const monthStart = date.startOf('month'); const monthEnd = date.endOf('month');
try { const response = await fetch( '/api/events?start=' + monthStart.toISOString() + '&end=' + monthEnd.toISOString() );
if (response.ok) { const monthEvents = await response.json(); setEvents(monthEvents); } } catch (error) { console.error('Failed to load events for date:', error); } };
return ( <div className="relative"> {loading && ( <div className="absolute inset-0 bg-white/50 flex items-center justify-center z-10"> <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div> </div> )}
<IlamyCalendar events={events} initialView="month" onEventAdd={handleEventAdd} onEventUpdate={handleEventUpdate} onEventDelete={handleEventDelete} onDateChange={handleDateChange} onEventClick={(event) => { // Navigate to event details or open modal console.log('Event clicked:', event); }} /> </div> );}CalendarEvent Interface
Section titled “CalendarEvent Interface”The main event object used throughout the calendar. All events passed to the calendar should conform to this interface.
interface CalendarEvent { id: string; // Unique identifier for the event title: string; // Display title of the event start: Date; // Start date and time end: Date; // End date and time description?: string; // Optional description text color?: string; // Optional text color (hex, rgb, named colors, class names) backgroundColor?: string; // Optional background color (hex, rgb, named colors, class names) allDay?: boolean; // Whether this is an all-day event resourceId?: string | number; // Single resource assignment (for resource calendars) resourceIds?: (string | number)[]; // Multiple resource assignment (for cross-resource events) data?: Record<string, any>; // Optional custom data for additional properties}Event Properties Explained
Section titled “Event Properties Explained”Required Properties
Section titled “Required Properties”id- Must be unique across all events. Used for drag-and-drop and event updates.title- The text displayed on the event in the calendar.start- JavaScript Date object representing when the event begins.end- JavaScript Date object representing when the event ends.
Optional Properties
Section titled “Optional Properties”description- Additional text shown in tooltips or custom event renderers.color- Background color for the event. Supports hex (#ff0000), rgb(255,0,0), or named colors (red).allDay- When true, the event spans the entire day and ignores time components.
Example Event Objects
Section titled “Example Event Objects”// Regular timed eventconst meeting = { id: 'meeting-1', title: 'Team Standup', start: new Date('2024-01-15T09:00:00'), end: new Date('2024-01-15T09:30:00'), description: 'Daily team sync meeting', color: '#3b82f6'};
// All-day eventconst holiday = { id: 'holiday-1', title: 'National Holiday', start: new Date('2024-01-01'), end: new Date('2024-01-01'), allDay: true, color: '#ef4444'};
// Multi-day eventconst conference = { id: 'conf-1', title: 'Tech Conference', start: new Date('2024-01-20T08:00:00'), end: new Date('2024-01-22T18:00:00'), description: 'Annual technology conference', color: '#10b981'};BusinessHours Interface
Section titled “BusinessHours Interface”Configuration object for restricting calendar interactions to specific days and time ranges. Used with the businessHours prop. Supports both single object (same hours for all days) and array format (different hours per day).
interface BusinessHours { // Array of day names considered business days daysOfWeek: ('monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday' | 'sunday')[];
// Hour when business hours start (0-23, inclusive) startTime: number;
// Hour when business hours end (0-23, exclusive) endTime: number;}Usage Examples
Section titled “Usage Examples”Standard business hours (same for all days):
const businessHours: BusinessHours = { daysOfWeek: ['monday', 'tuesday', 'wednesday', 'thursday', 'friday'], startTime: 9, endTime: 17,};
<IlamyCalendar events={events} businessHours={businessHours}/>Different hours per day (array format):
const businessHours: BusinessHours[] = [ { daysOfWeek: ['monday', 'wednesday', 'friday'], startTime: 9, endTime: 17, }, { daysOfWeek: ['tuesday', 'thursday'], startTime: 10, endTime: 18, }, { daysOfWeek: ['saturday'], startTime: 11, endTime: 15, },];
<IlamyCalendar events={events} businessHours={businessHours}/>CellClickInfo Interface
Section titled “CellClickInfo Interface”Information passed to the onCellClick callback. Uses named properties for better extensibility and clarity.
interface CellClickInfo { // Start date/time of the clicked cell start: dayjs.Dayjs;
// End date/time of the clicked cell end: dayjs.Dayjs;
// Resource ID if clicking on a resource calendar cell (optional) resourceId?: string | number;}Usage Example
Section titled “Usage Example”Handle cell clicks with the new CellClickInfo object:
const handleCellClick = (info: CellClickInfo) => { const { start, end, resourceId } = info; console.log('Cell clicked from', start.format(), 'to', end.format());
// For resource calendars, resourceId will be available if (resourceId) { console.log('On resource:', resourceId); }
// Create a new event openEventForm({ start, end, resourceId });};
<IlamyCalendar events={events} onCellClick={handleCellClick}/>ClassesOverride Interface
Section titled “ClassesOverride Interface”Custom class names to override default styling for various calendar elements. Used with the classesOverride prop to customize the appearance of calendar components.
interface ClassesOverride { // Custom class name for disabled cells // Applied to: cells outside business hours/days, and days from other months in month view disabledCell?: string;}Usage Example
Section titled “Usage Example”Customize the styling of disabled cells:
const classesOverride: ClassesOverride = { disabledCell: 'opacity-30 bg-gray-100 cursor-not-allowed',};
<IlamyCalendar events={events} businessHours={{ daysOfWeek: ['monday', 'tuesday', 'wednesday', 'thursday', 'friday'], startTime: 9, endTime: 17, }} classesOverride={classesOverride}/>EventFormProps Interface
Section titled “EventFormProps Interface”Props passed to custom event form components via the renderEventForm prop. Use this interface to build your own event creation and editing forms.
interface EventFormProps { // Whether the form should be displayed open?: boolean;
// The event being edited (null/undefined for new events) selectedEvent?: CalendarEvent | null;
// Callback to create a new event onAdd?: (event: CalendarEvent) => void;
// Callback to update an existing event onUpdate?: (event: CalendarEvent) => void;
// Callback to delete an event onDelete?: (event: CalendarEvent) => void;
// Callback to close the form (required) onClose: () => void;}Usage Example
Section titled “Usage Example”Implementing a custom event form with EventFormProps:
const MyEventForm = (props: EventFormProps) => { const { open, selectedEvent, onAdd, onUpdate, onDelete, onClose } = props;
if (!open) return null;
return ( <div className="modal"> <h2>{selectedEvent ? 'Edit Event' : 'New Event'}</h2> {/* Your custom form UI */} <button onClick={onClose}>Close</button> </div> );};
// Usage<IlamyCalendar events={events} renderEventForm={(props) => <MyEventForm {...props} />}/>