@fullcalendar/daygrid vs @fullcalendar/list vs @fullcalendar/timegrid
Architecting Calendar Views: Selecting the Right FullCalendar Plugin for Your Data Model
@fullcalendar/daygrid@fullcalendar/list@fullcalendar/timegridSimilar Packages:

Architecting Calendar Views: Selecting the Right FullCalendar Plugin for Your Data Model

@fullcalendar/daygrid, @fullcalendar/list, and @fullcalendar/timegrid are official plugins for the FullCalendar library, each rendering event data in a distinct visual format. daygrid provides the classic month view with events stacked in cells, ideal for high-level overviews. timegrid offers detailed day and week views with a vertical time axis, supporting precise scheduling and drag-and-drop resizing. list presents events as a linear, scrollable agenda, optimized for mobile consumption or dense data lists. Together, they allow developers to compose a complete calendar application by switching views based on user context without changing the underlying data structure.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
@fullcalendar/daygrid020,632202 kB1,1283 months agoMIT
@fullcalendar/list020,63268.3 kB1,1283 months agoMIT
@fullcalendar/timegrid020,632237 kB1,1283 months agoMIT

Architecting Calendar Views: Selecting the Right FullCalendar Plugin for Your Data Model

When integrating a calendar into a modern web application, the data model usually remains constant: a list of events with titles, start dates, and end dates. However, how users consume that data varies wildly depending on their device and goals. The FullCalendar ecosystem solves this by splitting rendering logic into modular plugins: @fullcalendar/daygrid, @fullcalendar/timegrid, and @fullcalendar/list. Choosing the right one isn't just about aesthetics; it's about matching the visualization to the user's workflow.

đź“… Visual Density: Month Grids vs. Time Axes vs. Linear Lists

The most obvious difference is how these packages map time to screen space.

@fullcalendar/daygrid compresses time into fixed cells. It treats a day as a single bucket. Whether an event lasts 15 minutes or 12 hours, it appears as a bar within that day's cell. This is perfect for spotting "busy weeks" but terrible for seeing gaps between meetings.

// daygrid: Events are stacked in day cells
import { Calendar } from '@fullcalendar/core';
import dayGridPlugin from '@fullcalendar/daygrid';

const calendar = new Calendar(calendarEl, {
  plugins: [dayGridPlugin],
  initialView: 'dayGridMonth',
  events: [
    { title: 'Short Meeting', start: '2023-10-10T10:00:00', end: '2023-10-10T10:30:00' },
    { title: 'All Day Conference', start: '2023-10-10', end: '2023-10-11' }
  ]
});

@fullcalendar/timegrid introduces a vertical Y-axis representing hours. It renders events as absolute blocks positioned by their start and end times. This reveals the actual duration and空闲 (free) time between events, which is critical for scheduling.

// timegrid: Events are positioned by exact time
import timeGridPlugin from '@fullcalendar/timegrid';

const calendar = new Calendar(calendarEl, {
  plugins: [timeGridPlugin],
  initialView: 'timeGridWeek',
  slotMinTime: '08:00:00', // Start view at 8 AM
  events: [
    { title: 'Short Meeting', start: '2023-10-10T10:00:00', end: '2023-10-10T10:30:00' },
    { title: 'Lunch', start: '2023-10-10T12:00:00', end: '2023-10-10T13:00:00' }
  ]
});

@fullcalendar/list abandons the grid entirely. It renders a simple, scrollable list of events sorted by date. This removes all spatial guessing games; if an event exists, it's a row in the list. This is highly effective for mobile devices where horizontal space is limited.

// list: Events are rows in a chronological feed
import listPlugin from '@fullcalendar/list';

const calendar = new Calendar(calendarEl, {
  plugins: [listPlugin],
  initialView: 'listWeek',
  listDayFormat: { month: 'long', day: 'numeric', weekday: 'long' },
  events: [
    { title: 'Short Meeting', start: '2023-10-10T10:00:00' },
    { title: 'Lunch', start: '2023-10-10T12:00:00' }
  ]
});

âś‹ Interaction Models: Drag-and-Drop Capabilities

Interaction design differs significantly because the spatial metaphors are different.

@fullcalendar/daygrid supports dragging events from one day to another. However, it cannot handle time-based resizing. If you try to resize an event here, you are typically extending it to cover more full days, not more hours.

// daygrid: Drag to change the DAY, not the hour
const calendar = new Calendar(calendarEl, {
  plugins: [dayGridPlugin],
  editable: true, // Enables dragging
  eventDrop: function(info) {
    // info.event.start has moved to a new date, time remains same relative to day
    console.log(`Moved to ${info.event.start.toLocaleDateString()}`);
  }
});

@fullcalendar/timegrid offers the richest interaction model. Users can drag events to change the start time, or grab the bottom edge to resize the duration in minutes. This requires precise mouse/touch mapping to the time axis.

// timegrid: Drag to change TIME, resize to change DURATION
const calendar = new Calendar(calendarEl, {
  plugins: [timeGridPlugin],
  editable: true,
  eventResize: function(info) {
    // info.event.end has changed, reflecting a new duration
    const durationMs = info.event.end - info.event.start;
    console.log(`New duration: ${durationMs / 1000 / 60} minutes`);
  }
});

@fullcalendar/list generally disables complex spatial interactions like dragging to reorder or resizing, as there is no spatial grid to map to. Interactions here are usually limited to clicking an event to open a detail modal or a dedicated "edit" button.

// list: Click to interact, no spatial dragging
const calendar = new Calendar(calendarEl, {
  plugins: [listPlugin],
  eventClick: function(info) {
    // Standard pattern: open a modal for edits
    alert(`Edit event: ${info.event.title}`);
    // Dragging is typically disabled or meaningless in list view
  }
});

📱 Responsive Strategy: When to Switch Views

In professional applications, you rarely pick just one. You architect the system to switch views based on viewport width or user preference.

Scenario A: The Desktop Dashboard On large screens, users expect the power of timegrid for scheduling. They need to see the 9:00 AM gap between meetings.

// Desktop-first configuration
const calendar = new Calendar(calendarEl, {
  plugins: [timeGridPlugin, dayGridPlugin],
  initialView: 'timeGridWeek',
  headerToolbar: {
    left: 'prev,next today',
    center: 'title',
    right: 'dayGridMonth,timeGridWeek,timeGridDay' // Allow switching
  }
});

Scenario B: The Mobile Companion On phones, timegrid often becomes unusable because the time labels and event blocks get too squished. The architectural pattern here is to detect screen size and force the list view or dayGridMonth.

// Mobile-responsive logic
const isMobile = window.innerWidth < 768;

const calendar = new Calendar(calendarEl, {
  plugins: [listPlugin, dayGridPlugin],
  initialView: isMobile ? 'listWeek' : 'dayGridMonth',
  headerToolbar: {
    left: 'prev,next',
    center: 'title',
    right: isMobile ? 'listDay,listWeek' : 'dayGridMonth,prev,next'
  }
});

⚙️ Performance and Data Handling

All three plugins share the same core event parsing engine, so raw data loading performance is identical. The difference lies in DOM complexity.

  • daygrid renders a fixed grid (7 columns x 5-6 rows). It is very performant even with hundreds of events because events are simply appended into cells. However, if a single day has 50+ events, the cell height expands, potentially breaking layout.
  • timegrid is the most DOM-heavy. It renders time slots (every 15 or 30 mins) for every day in view. With many events, collision detection logic (to place events side-by-side) can cause slight rendering delays on low-end devices.
  • list is the most performant for large datasets. It uses virtualization techniques (rendering only visible rows) in newer versions or simply relies on native browser scrolling. It handles thousands of events gracefully because it doesn't calculate complex grid positions.
// Handling large datasets efficiently
// All plugins use the same event source, but List handles rendering best
const calendar = new Calendar(calendarEl, {
  plugins: [listPlugin, timeGridPlugin],
  events: '/api/heavy-load-events', // JSON feed
  eventLimit: true, // Specific to daygrid: "+5 more" link if too many events
  // list view has no eventLimit needed; it just scrolls
});

🌱 Shared Ground: The Core API

Despite their visual differences, these packages are unified by the FullCalendar core. You do not need to rewrite your data fetching or state management logic when switching views.

1. 🔄 Unified Event Data Structure

Regardless of the view, events are defined identically. You don't need special "list events" or "grid events".

// Works identically in daygrid, timegrid, and list
const events = [
  {
    id: '1',
    title: 'Project Review',
    start: '2023-11-01T14:00:00',
    end: '2023-11-01T15:00:00',
    backgroundColor: '#3788d8'
  }
];

2. 🎨 Consistent Styling Hooks

CSS classes and rendering callbacks (like eventContent) work across all plugins. You can inject custom HTML (like avatars or status dots) into any view.

// Custom rendering works in all views
const calendar = new Calendar(calendarEl, {
  plugins: [dayGridPlugin, timeGridPlugin, listPlugin],
  eventContent: function(arg) {
    // Returns custom HTML for the event body
    return { html: `<b>${arg.timeText}</b> <i>${arg.event.title}</i>` };
  }
});

3. 🔌 Plugin Composition

You can load multiple plugins simultaneously and let the user toggle between them via the toolbar. There is no performance penalty for loading the code; the penalty is only in rendering the active view.

// Load all three, let user choose
import interactionPlugin from '@fullcalendar/interaction';

const calendar = new Calendar(calendarEl, {
  plugins: [dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin],
  initialView: 'dayGridMonth',
  headerToolbar: {
    right: 'dayGridMonth,timeGridWeek,listWeek' // User switches here
  }
});

📊 Summary: Feature Matrix

Feature@fullcalendar/daygrid@fullcalendar/timegrid@fullcalendar/list
Primary ViewMonth GridWeek / Day ColumnsScrollable List
Time PrecisionLow (Day level)High (Minute level)Medium (Text display)
Drag & DropMove between daysMove time + Resize durationDisabled (Click to edit)
Best ForOverview, PlanningScheduling, AdminMobile, Dense Data
DOM ComplexityLowHighLow
Event OverlapStacked in cellSide-by-side columnsLinear rows

đź’ˇ The Big Picture

Think of these packages as different lenses for the same data.

@fullcalendar/daygrid is the wide-angle lens. Use it when users need context—"What does my month look like?" It's the default for a reason: it's familiar and low-cognitive load.

@fullcalendar/timegrid is the macro lens. Use it when users need to operate—"Where exactly can I fit this 45-minute call?" It demands more screen real estate but pays off in utility for power users.

@fullcalendar/list is the focus lens. Use it when users need clarity—"What is happening next?" It strips away the grid metaphor entirely to prioritize content readability, making it the unsung hero of mobile responsiveness.

Final Thought: You rarely have to choose just one forever. The most robust architecture loads all three and uses CSS media queries or JavaScript logic to swap the initialView and toolbar buttons based on the user's device, ensuring the right tool is always available for the job.

How to Choose: @fullcalendar/daygrid vs @fullcalendar/list vs @fullcalendar/timegrid

  • @fullcalendar/daygrid:

    Choose @fullcalendar/daygrid when your primary goal is to provide a high-level monthly overview where users need to spot patterns or busy periods at a glance. It is the standard choice for dashboards, marketing sites, or any scenario where exact start/end times are less critical than the date of occurrence. Avoid this package if your users need to schedule meetings down to the minute or if your events vary significantly in duration within a single day, as it compresses time information.

  • @fullcalendar/list:

    Choose @fullcalendar/list when building mobile-first interfaces or when your event data is too dense to fit comfortably in a grid layout. It excels in scenarios where users need a linear, chronological feed of upcoming items, similar to an email inbox or a task list. This is the best fallback view for small screens where grid cells become too small to interact with, ensuring accessibility and readability without complex responsive logic.

  • @fullcalendar/timegrid:

    Choose @fullcalendar/timegrid for applications centered around scheduling, resource management, or appointment booking where time precision is paramount. This package is essential if users need to drag events to specific times, resize them visually, or view multiple days side-by-side with a consistent time axis. It is the heavy lifter for admin panels and enterprise tools, but it may feel too dense for mobile users or simple read-only displays.

README for @fullcalendar/daygrid

FullCalendar Day Grid Plugin

Display events on a month view or "day grid" view

Installation

Install the necessary packages:

npm install @fullcalendar/core @fullcalendar/daygrid

Usage

Instantiate a Calendar with the necessary plugin:

import { Calendar } from '@fullcalendar/core'
import dayGridPlugin from '@fullcalendar/daygrid'

const calendarEl = document.getElementById('calendar')
const calendar = new Calendar(calendarEl, {
  plugins: [dayGridPlugin],
  initialView: 'dayGridMonth',
  events: [
    { title: 'Meeting', start: new Date() }
  ]
})

calendar.render()