Skip to main content

Overview

The UnifiedCalendar component provides a complete calendar solution that combines both monthly and weekly views in a single interface. It includes built-in view switching controls, navigation, and event rendering capabilities, making it ideal for applications that need to display events in multiple calendar formats.

Import

import { UnifiedCalendar } from '@newtonschool/grauity';
import type { UnifiedCalendarProps, CalendarEvent } from '@newtonschool/grauity';

Basic Usage

import { UnifiedCalendar } from '@newtonschool/grauity';
import { useState } from 'react';

function MyCalendar() {
  const [date, setDate] = useState(new Date());
  const [view, setView] = useState('monthly');

  const events = [
    {
      id: '1',
      title: 'Team Meeting',
      start: new Date(2024, 2, 15, 10, 0),
      end: new Date(2024, 2, 15, 11, 0),
    },
    {
      id: '2',
      title: 'Project Review',
      start: new Date(2024, 2, 20, 14, 0),
      end: new Date(2024, 2, 20, 15, 30),
    },
  ];

  return (
    <UnifiedCalendar
      date={date}
      onDateChange={setDate}
      view={view}
      onViewChange={setView}
      events={events}
      eventRenderer={(event, view) => (
        <div>
          {event.title}
        </div>
      )}
    />
  );
}

Props

events
CalendarEvent<T>[]
required
Array of events to display in the calendar. Each event must have start and end dates.
eventRenderer
(item: CalendarEvent<T>, view: CalendarView) => React.ReactNode
required
Function to render each event. Receives the event data and current view type (‘monthly’ or ‘weekly’) as parameters.
date
Date
required
The date for which the calendar should render events.
view
'monthly' | 'weekly'
default:"'weekly'"
Calendar view to display. Controls whether the calendar shows the monthly or weekly layout.
onViewChange
(viewType: CalendarView) => void
Callback fired when the user switches between monthly and weekly views.
onDateChange
(date: Date) => void
Callback fired when the date changes through navigation controls.
shouldShowControls
boolean
default:"true"
Whether to show view switching tabs and navigation controls in the header.
header
React.ReactNode
default:"null"
Custom header content to display above the calendar controls.
loading
boolean
default:"false"
Whether the calendar is in a loading state. Shows placeholder UI when true.
className
string
default:"''"
Additional class name for the calendar wrapper element.

Weekly Calendar Props

weeklyCalendarProps
object
Configuration options specific to the weekly calendar view.

Monthly Calendar Props

monthlyCalendarProps
object
Configuration options specific to the monthly calendar view.

Event Data Structure

The CalendarEvent interface defines the structure for calendar events:
interface CalendarEvent<T = {}> {
  id?: string | number;
  title?: string;
  start: Date;        // Required: Event start time
  end: Date;          // Required: Event end time
  allDay?: boolean;
  render?: (event: CalendarEvent<T>) => React.ReactNode;
  focused?: boolean;  // Highlights the event
}

Complete Example with Custom Event Rendering

import { UnifiedCalendar } from '@newtonschool/grauity';
import MonthlyCalendarEventItem from '@newtonschool/grauity';
import { useState } from 'react';

function CalendarApp() {
  const [date, setDate] = useState(new Date());
  const [view, setView] = useState('monthly');

  const events = [
    {
      id: '1',
      title: 'Morning Meeting',
      start: new Date(2024, 2, 7, 9, 0),
      end: new Date(2024, 2, 7, 10, 30),
    },
    {
      id: '2',
      title: 'Team Lunch',
      start: new Date(2024, 2, 7, 12, 0),
      end: new Date(2024, 2, 7, 13, 0),
    },
    {
      id: '3',
      title: 'Project Review',
      start: new Date(2024, 2, 10, 11, 0),
      end: new Date(2024, 2, 10, 12, 30),
    },
  ];

  return (
    <div style={{ height: '100vh' }}>
      <UnifiedCalendar
        date={date}
        onDateChange={setDate}
        view={view}
        onViewChange={setView}
        events={events}
        eventRenderer={(event, viewType) => (
          <MonthlyCalendarEventItem
            key={event.id}
            eventTime={event.start}
            eventTitle={event.title}
            eventTitleColor="var(--text-emphasis-invert-primary-default, #ffffff)"
            eventTimeColor="var(--text-emphasis-invert-primary-default, #ffffff)"
            backgroundColor="var(--bg-emphasis-brand-default, #0673f9)"
            height="50px"
          />
        )}
        shouldShowControls
        weeklyCalendarProps={{
          defaultScrollHour: 8,
          shouldScrollToFirstEvent: true,
        }}
        monthlyCalendarProps={{
          onPopOverClose: () => console.log('Popover closed'),
        }}
      />
    </div>
  );
}

View Switching

The UnifiedCalendar automatically handles view transitions:
1

User clicks view tab

The header displays “Monthly” and “Weekly” tabs when shouldShowControls is true.
2

View state updates

The onViewChange callback fires with the new view type.
3

Calendar re-renders

The appropriate calendar component (Monthly or Weekly) renders with the same events and date.

Custom Header

You can add custom content above the calendar controls:
<UnifiedCalendar
  header={
    <div style={{ padding: '16px' }}>
      <h2>Team Schedule</h2>
      <p>View and manage team events</p>
    </div>
  }
  // ... other props
/>

Loading State

<UnifiedCalendar
  loading={true}
  events={[]}
  // ... other props
/>
When loading is true, the calendar displays placeholder elements instead of actual events.

Accessibility

  • The calendar wrapper has appropriate ARIA labels describing the current view
  • Navigation buttons include descriptive aria-label attributes
  • Keyboard navigation is fully supported
  • All interactive elements are keyboard accessible

Best Practices

Keep event data in a state management solution when dealing with large datasets. The calendar efficiently handles hundreds of events, but consider pagination for very large collections.
Store the user’s preferred view in localStorage or your backend to maintain consistency across sessions.
Always keep the date prop synchronized with your application state to ensure the calendar displays the correct time period.
Memoize your event renderer function if it performs expensive computations to avoid unnecessary re-renders.

TypeScript

The component is fully typed with generic support for custom event data:
interface CustomEventData {
  priority: 'high' | 'medium' | 'low';
  attendees: string[];
}

const events: CalendarEvent<CustomEventData>[] = [
  {
    id: '1',
    title: 'Meeting',
    start: new Date(),
    end: new Date(),
    priority: 'high',
    attendees: ['[email protected]', '[email protected]'],
  },
];

<UnifiedCalendar<CustomEventData>
  events={events}
  eventRenderer={(event) => (
    <div>
      {event.title} - Priority: {event.priority}
    </div>
  )}
  // ... other props
/>

WeeklyCalendar

Week-based calendar view with time slots

MonthlyCalendar

Month-based calendar grid view

Build docs developers (and LLMs) love