V7 JavaScript API Migration Guide
Table of Contents
- Before You Begin
- Connectors
- Toolbar
- Events (General)
- Resources (General)
- Calendar Views
- Plugins
- Custom Theme Class
- Locales
- Interactions
- Misc
This document will help you migrate from v6 of the API to v7. It centers around JS settings that must be changed. If you’ve written custom CSS, see the CSS migration guide instead.
Before You Begin
Components in Examples
Many examples show React component pseudo-code with the <FullCalendar> element. Please adapt these examples to Vue or Angular, minding the way FullCalendar treats components and component props for each library.
clsx
Many migrations in this document show the merging of multiple class-names with the clsx utility. It’s especially important for conditional class-names. Installation:
npm install --save clsx In the JS:
import clsx from 'clsx'
const bool = true
clsx('you', 'can', 'merge', bool && 'okay?') // "you can merge okay?" React
React Standard Packages
Breaking: dependency changes:
@fullcalendar/coreremoved as a peer dependency@fullcalendar/daygridand many other packages removed and moved to@fullcalendar/react/*entrypoints (seepackage.jsonbelow)temporal-polyfilladded as a peer dependency
1) So, your package.json should be modified:
{
"dependencies": {
- "@fullcalendar/react": "^6.1.20",
+ "@fullcalendar/react": "7@beta",
- "@fullcalendar/core": "^6.1.20",
- "@fullcalendar/interaction": "^6.1.20",
- "@fullcalendar/daygrid": "^6.1.20",
- "@fullcalendar/timegrid": "^6.1.20",
- "@fullcalendar/list": "^6.1.20",
- "@fullcalendar/multimonth": "^6.1.20",
}
} 2) Then install temporal-polyfill:
npm install --save temporal-polyfill 3) In your JS, change your imports:
import interactionPlugin
- from '@fullcalendar/interaction'
+ from '@fullcalendar/react/interaction'
import dayGridPlugin
- from '@fullcalendar/daygrid'
+ from '@fullcalendar/react/daygrid'
import timeGridPlugin
- from '@fullcalendar/timegrid'
+ from '@fullcalendar/react/timegrid'
import listPlugin
- from '@fullcalendar/list'
+ from '@fullcalendar/react/list'
import multiMonthPlugin
- from '@fullcalendar/multimonth'
+ from '@fullcalendar/react/multimonth' React Scheduler Packages
Breaking: additional dependency changes for premium (aka “scheduler”):
1) Remove the following packages from your package.json:
{
"dependencies": {
"@fullcalendar/react": "7@beta",
...
- "@fullcalendar/resource": "^6.1.20",
- "@fullcalendar/adaptive": "^6.1.20",
- "@fullcalendar/scrollgrid": "^6.1.20",
- "@fullcalendar/timeline": "^6.1.20",
- "@fullcalendar/resource-timeline": "^6.1.20",
- "@fullcalendar/resource-timegrid": "^6.1.20"
}
} 2) Install the @fullcalendar/react-scheduler package:
npm install --save @fullcalendar/react-scheduler@beta 3) In your JS, change your imports:
import resourcePlugin
- from '@fullcalendar/resource'
+ from '@fullcalendar/react-scheduler'
import adaptivePlugin
- from '@fullcalendar/adaptive'
+ from '@fullcalendar/react-scheduler/adaptive'
import scrollGridPlugin
- from '@fullcalendar/scrollgrid'
+ from '@fullcalendar/react-scheduler/scrollgrid'
import timelinePlugin
- from '@fullcalendar/timeline'
+ from '@fullcalendar/react-scheduler/timeline'
import resourceTimelinePlugin
- from '@fullcalendar/resource-timeline'
+ from '@fullcalendar/react-scheduler/resource-timeline'
import resourceTimeGridPlugin
- from '@fullcalendar/resource-timegrid'
+ from '@fullcalendar/react-scheduler/resource-timegrid' Breaking: FullCalendar no longer bundles its own CSS. Furthermore, the calendar “theme” has been pulled out from the core, as a plugin. Thus, you must import your own stylesheets. This depends on what theme you choose (see themes.fullcalendar.io):
import FullCalendar from '@fullcalendar/react'
+ import themePlugin from '@fullcalendar/react/themes/classic'
// import other plugins...
// stylesheets
+ import '@fullcalendar/react/skeleton.css' // ALWAYS NEED SKELETON
+ import '@fullcalendar/react/themes/classic/theme.css' // YOUR THEME
+ import '@fullcalendar/react/themes/classic/palette.css' // YOUR THEME'S PALETTE
<FullCalendar
plugins={[
+ themePlugin,
// other plugins here...
]}
/> Remix
Behavior: The Remix framework previously required a hack to explicitly define the DOM-placement for styles, but this is no longer needed. In app/root.tsx:
function Document({
children,
title,
}: {
children: React.ReactNode;
title?: string;
}) {
return (
<html lang="en">
<head>
{title ? <title>{title}</title> : null}
<Meta />
- <style data-fullcalendar ></style>
<Links />
</head>
<body>
{children}
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
} Vue
Vue Standard Packages
Breaking: dependency changes:
@fullcalendar/coreremoved as a peer dependency@fullcalendar/daygridand many other packages removed and moved to@fullcalendar/vue3/*entrypoints (seepackage.jsonbelow)temporal-polyfilladded as a peer dependency
1) So, your package.json should be modified:
{
"dependencies": {
- "@fullcalendar/vue3": "^6.1.20",
+ "@fullcalendar/vue3": "7@beta",
- "@fullcalendar/core": "^6.1.20",
- "@fullcalendar/interaction": "^6.1.20",
- "@fullcalendar/daygrid": "^6.1.20",
- "@fullcalendar/timegrid": "^6.1.20",
- "@fullcalendar/list": "^6.1.20",
- "@fullcalendar/multimonth": "^6.1.20"
}
} 2) Then install temporal-polyfill:
npm install --save temporal-polyfill 3) In your JS, change your imports:
import interactionPlugin
- from '@fullcalendar/interaction'
+ from '@fullcalendar/vue3/interaction'
import dayGridPlugin
- from '@fullcalendar/daygrid'
+ from '@fullcalendar/vue3/daygrid'
import timeGridPlugin
- from '@fullcalendar/timegrid'
+ from '@fullcalendar/vue3/timegrid'
import listPlugin
- from '@fullcalendar/list'
+ from '@fullcalendar/vue3/list'
import multiMonthPlugin
- from '@fullcalendar/multimonth'
+ from '@fullcalendar/vue3/multimonth' Vue Scheduler Packages
Breaking: additional dependency changes for premium (aka “scheduler”):
1) Remove the following packages from your package.json:
{
"dependencies": {
"@fullcalendar/vue3": "7@beta",
...
- "@fullcalendar/resource": "^6.1.20",
- "@fullcalendar/adaptive": "^6.1.20",
- "@fullcalendar/scrollgrid": "^6.1.20",
- "@fullcalendar/timeline": "^6.1.20",
- "@fullcalendar/resource-timeline": "^6.1.20",
- "@fullcalendar/resource-timegrid": "^6.1.20"
}
} 2) Install the @fullcalendar/vue3-scheduler package:
npm install --save @fullcalendar/vue3-scheduler@beta 3) In your JS, change your imports:
import resourcePlugin
- from '@fullcalendar/resource'
+ from '@fullcalendar/vue3-scheduler'
import adaptivePlugin
- from '@fullcalendar/adaptive'
+ from '@fullcalendar/vue3-scheduler/adaptive'
import scrollGridPlugin
- from '@fullcalendar/scrollgrid'
+ from '@fullcalendar/vue3-scheduler/scrollgrid'
import timelinePlugin
- from '@fullcalendar/timeline'
+ from '@fullcalendar/vue3-scheduler/timeline'
import resourceTimelinePlugin
- from '@fullcalendar/resource-timeline'
+ from '@fullcalendar/vue3-scheduler/resource-timeline'
import resourceTimeGridPlugin
- from '@fullcalendar/resource-timegrid'
+ from '@fullcalendar/vue3-scheduler/resource-timegrid' Breaking: FullCalendar no longer bundles its own CSS. Furthermore, the calendar “theme” has been pulled out from the core, as a plugin. Thus, you must import your own stylesheets. This depends on what theme you choose (see themes.fullcalendar.io):
<script setup>
import FullCalendar from '@fullcalendar/vue3'
+ import themePlugin from '@fullcalendar/vue3/themes/classic'
// import other plugins...
// stylesheets
+ import '@fullcalendar/vue3/skeleton.css' // ALWAYS NEED SKELETON
+ import '@fullcalendar/vue3/themes/classic/theme.css' // YOUR THEME
+ import '@fullcalendar/vue3/themes/classic/palette.css' // YOUR THEME'S PALETTE
</script>
<template>
<FullCalendar
:options="{
plugins: [
+ themePlugin,
// other plugins here...
],
}"
/>
</template> Angular
Angular Standard Packages
Breaking: dependency changes:
- The
@fullcalendar/corepeer dependency has been renamedfullcalendar @fullcalendar/daygridand many other packages removed and moved to@fullcalendar/angular/*entrypoints (seepackage.jsonbelow)temporal-polyfilladded as a peer dependency
1) So, your package.json should be modified:
{
"dependencies": {
- "@fullcalendar/angular": "^6.1.20",
+ "@fullcalendar/angular": "7@beta",
- "@fullcalendar/core": "^6.1.20",
- "@fullcalendar/interaction": "^6.1.20",
- "@fullcalendar/daygrid": "^6.1.20",
- "@fullcalendar/timegrid": "^6.1.20",
- "@fullcalendar/list": "^6.1.20",
- "@fullcalendar/multimonth": "^6.1.20"
}
} 2) Then install the two additional peer dependencies:
npm install --save fullcalendar@beta temporal-polyfill 3) In your JS, change your imports:
import interactionPlugin
- from '@fullcalendar/interaction'
+ from '@fullcalendar/angular/interaction'
import dayGridPlugin
- from '@fullcalendar/daygrid'
+ from '@fullcalendar/angular/daygrid'
import timeGridPlugin
- from '@fullcalendar/timegrid'
+ from '@fullcalendar/angular/timegrid'
import listPlugin
- from '@fullcalendar/list'
+ from '@fullcalendar/angular/list'
import multiMonthPlugin
- from '@fullcalendar/multimonth'
+ from '@fullcalendar/angular/multimonth' Angular Scheduler Packages
Breaking: additional dependency changes for premium (aka “scheduler”):
1) Remove the following packages from your package.json:
{
"dependencies": {
"@fullcalendar/angular": "7@beta",
"fullcalendar": "7@beta",
...
- "@fullcalendar/resource": "^6.1.20",
- "@fullcalendar/adaptive": "^6.1.20",
- "@fullcalendar/scrollgrid": "^6.1.20",
- "@fullcalendar/timeline": "^6.1.20",
- "@fullcalendar/resource-timeline": "^6.1.20",
- "@fullcalendar/resource-timegrid": "^6.1.20"
}
} 2) Install the @fullcalendar/angular-scheduler package:
npm install --save @fullcalendar/angular-scheduler@beta 3) In your JS, change your imports:
import resourcePlugin
- from '@fullcalendar/resource'
+ from '@fullcalendar/angular-scheduler'
import adaptivePlugin
- from '@fullcalendar/adaptive'
+ from '@fullcalendar/angular-scheduler/adaptive'
import scrollGridPlugin
- from '@fullcalendar/scrollgrid'
+ from '@fullcalendar/angular-scheduler/scrollgrid'
import timelinePlugin
- from '@fullcalendar/timeline'
+ from '@fullcalendar/angular-scheduler/timeline'
import resourceTimelinePlugin
- from '@fullcalendar/resource-timeline'
+ from '@fullcalendar/angular-scheduler/resource-timeline'
import resourceTimeGridPlugin
- from '@fullcalendar/resource-timegrid'
+ from '@fullcalendar/angular-scheduler/resource-timegrid' Breaking: FullCalendar no longer bundles its own CSS. Furthermore, the calendar “theme” has been pulled out from the core, as a plugin. Thus, you must import your own stylesheets. This depends on what theme you choose (see themes.fullcalendar.io):
import { FullCalendarModule } from '@fullcalendar/angular';
import { FullCalendarModule, CalendarOptions } from '@fullcalendar/angular';
+ import themePlugin from '@fullcalendar/angular/themes/classic'; // YOUR THEME
// import other plugins...
export class App {
calendarOptions = signal<CalendarOptions>({
plugins: [
+ themePlugin,
// other plugins here...
],
}) Add the following stylesheets to your angular.json:
{
"projects": { // ...
"my-project": { // ...
"architect": { // ...
"build": { // ...
"options": { // ...
"styles": [
+ "@fullcalendar/angular/skeleton.css", // ALWAYS NEED SKELETON
+ "@fullcalendar/angular/themes/classic/theme.css", // YOUR THEME
+ "@fullcalendar/angular/themes/classic/palette.css", // YOUR THEME'S PALETTE
"src/styles.css"
] Vanilla JS
Vanilla JS Standard Packages
Breaking: dependency changes:
- Vanilla JS package
@fullcalendar/corerenamed tofullcalendar @fullcalendar/daygridand many other packages removed and moved tofullcalendar/*entrypoints (seepackage.jsonbelow)temporal-polyfilladded as a peer dependency
1) So, your package.json should be modified:
{
"dependencies": {
- "@fullcalendar/core": "^6.1.20",
- "@fullcalendar/interaction": "^6.1.20",
- "@fullcalendar/daygrid": "^6.1.20",
- "@fullcalendar/timegrid": "^6.1.20",
- "@fullcalendar/list": "^6.1.20",
- "@fullcalendar/multimonth": "^6.1.20"
}
} 2) Then install the renamed vanilla JS connector and temporal-polyfill:
npm install --save fullcalendar@beta temporal-polyfill 3) In your JS, change your imports:
import interactionPlugin
- from '@fullcalendar/interaction'
+ from 'fullcalendar/interaction' // no @ at the beginning!
import dayGridPlugin
- from '@fullcalendar/daygrid'
+ from 'fullcalendar/daygrid' // no @ at the beginning!
import timeGridPlugin
- from '@fullcalendar/timegrid'
+ from 'fullcalendar/timegrid' // no @ at the beginning!
import listPlugin
- from '@fullcalendar/list'
+ from 'fullcalendar/list' // no @ at the beginning!
import multiMonthPlugin
- from '@fullcalendar/multimonth'
+ from 'fullcalendar/multimonth' // no @ at the beginning! Vanilla JS Scheduler Packages
Breaking: additional dependency changes for premium (aka “scheduler”):
1) Remove the following packages from your package.json:
{
"dependencies": {
"fullcalendar": "7@beta",
...
- "@fullcalendar/resource": "^6.1.20",
- "@fullcalendar/adaptive": "^6.1.20",
- "@fullcalendar/scrollgrid": "^6.1.20",
- "@fullcalendar/timeline": "^6.1.20",
- "@fullcalendar/resource-timeline": "^6.1.20",
- "@fullcalendar/resource-timegrid": "^6.1.20"
}
} 2) Install the fullcalendar-scheduler package:
npm install --save fullcalendar-scheduler@beta 3) In your JS, change your imports:
import resourcePlugin
- from '@fullcalendar/resource'
+ from 'fullcalendar-scheduler'
import adaptivePlugin
- from '@fullcalendar/adaptive'
+ from 'fullcalendar-scheduler/adaptive'
import scrollGridPlugin
- from '@fullcalendar/scrollgrid'
+ from 'fullcalendar-scheduler/scrollgrid'
import timelinePlugin
- from '@fullcalendar/timeline'
+ from 'fullcalendar-scheduler/timeline'
import resourceTimelinePlugin
- from '@fullcalendar/resource-timeline'
+ from 'fullcalendar-scheduler/resource-timeline'
import resourceTimeGridPlugin
- from '@fullcalendar/resource-timegrid'
+ from 'fullcalendar-scheduler/resource-timegrid' Breaking: FullCalendar no longer bundles its own CSS. Furthermore, the calendar “theme” has been pulled out from the core, as a plugin. Thus, you must import your own stylesheets. This depends on what theme you choose (see themes.fullcalendar.io):
- import { Calendar } from '@fullcalendar/core'
+ import { Calendar } from 'fullcalendar'
+ import themePlugin from 'fullcalendar/themes/classic' // YOUR THEME
// import other plugins...
// stylesheets
+ import 'fullcalendar/skeleton.css'
+ import 'fullcalendar/themes/classic/theme.css' // YOUR THEME
+ import 'fullcalendar/themes/classic/palette.css' // YOUR THEME'S PALETTE
const calendarEl = document.getElementById('calendar')
const calendar = new Calendar(calendarEl, {
plugins: [
+ themePlugin,
// other plugins here...
],
})
calendar.render() Global Script Tags
Breaking: index.global.js renamed to all.global.js (which contains “all” standard plugins), and additional scripts/stylesheets must be added for the theme:
<!-- STANDARD JS -->
- <script src='https://cdn.jsdelivr.net/npm/fullcalendar@6.1.20/index.global.js'></script>
+ <script src='https://cdn.jsdelivr.net/npm/fullcalendar@7.0.0-beta.7/all.global.js'></script>
<!-- THEME JS -->
+ <script src='https://cdn.jsdelivr.net/npm/fullcalendar@7.0.0-beta.7/themes/classic/global.js'></script>
<!-- STYLESHEETS -->
+ <link href='https://cdn.jsdelivr.net/npm/fullcalendar@7.0.0-beta.7/skeleton.css' rel='stylesheet' />
+ <link href='https://cdn.jsdelivr.net/npm/fullcalendar@7.0.0-beta.7/themes/classic/theme.css' rel='stylesheet' />
+ <link href='https://cdn.jsdelivr.net/npm/fullcalendar@7.0.0-beta.7/themes/classic/palette.css' rel='stylesheet' /> Breaking: Similar breaking changes for scheduler, but with an additional one: scheduler’s JS file no longer contains the standard plugins, so both standard and premium all.global.js files must be included:
<!-- STANDARD + SCHEDULER JS -->
- <script src='https://cdn.jsdelivr.net/npm/fullcalendar-scheduler@6.1.20/index.global.js'></script>
+ <script src='https://cdn.jsdelivr.net/npm/fullcalendar@7.0.0-beta.7/all.global.js'></script>
+ <script src='https://cdn.jsdelivr.net/npm/fullcalendar-scheduler@7.0.0-beta.7/all.global.js'></script>
<!-- THEME JS -->
+ <script src='https://cdn.jsdelivr.net/npm/fullcalendar@7.0.0-beta.7/themes/classic/global.js'></script>
<!-- STYLESHEETS -->
+ <link href='https://cdn.jsdelivr.net/npm/fullcalendar@7.0.0-beta.7/skeleton.css' rel='stylesheet' />
+ <link href='https://cdn.jsdelivr.net/npm/fullcalendar@7.0.0-beta.7/themes/classic/theme.css' rel='stylesheet' />
+ <link href='https://cdn.jsdelivr.net/npm/fullcalendar@7.0.0-beta.7/themes/classic/palette.css' rel='stylesheet' /> Web Component
Web Component Standard Packages
Breaking: dependency changes:
@fullcalendar/coreremoved as a peer dependency@fullcalendar/daygridand many other packages removed (seepackage.jsonbelow)temporal-polyfilladded as a peer dependency
1) So, your package.json should be modified:
{
"dependencies": {
- "@fullcalendar/web-component": "^6.1.20",
+ "@fullcalendar/web-component": "7@beta",
- "@fullcalendar/core": "^6.1.20",
- "@fullcalendar/interaction": "^6.1.20",
- "@fullcalendar/daygrid": "^6.1.20",
- "@fullcalendar/timegrid": "^6.1.20",
- "@fullcalendar/list": "^6.1.20",
- "@fullcalendar/multimonth": "^6.1.20"
}
} 2) Then install the upgraded web-component connector and temporal-polyfill:
npm install --save @fullcalendar/web-component@beta temporal-polyfill 3) In your JS, change your imports:
import interactionPlugin
- from '@fullcalendar/interaction'
+ from '@fullcalendar/web-component/interaction'
import dayGridPlugin
- from '@fullcalendar/daygrid'
+ from '@fullcalendar/web-component/daygrid'
import timeGridPlugin
- from '@fullcalendar/timegrid'
+ from '@fullcalendar/web-component/timegrid'
import listPlugin
- from '@fullcalendar/list'
+ from '@fullcalendar/web-component/list'
import multiMonthPlugin
- from '@fullcalendar/multimonth'
+ from '@fullcalendar/web-component/multimonth' Web Component Scheduler Packages
Breaking: additional dependency changes for premium (aka “scheduler”):
1) Remove the following packages from your package.json:
{
"dependencies": {
"@fullcalendar/web-component": "7@beta",
...
- "@fullcalendar/resource": "^6.1.20",
- "@fullcalendar/adaptive": "^6.1.20",
- "@fullcalendar/scrollgrid": "^6.1.20",
- "@fullcalendar/timeline": "^6.1.20",
- "@fullcalendar/resource-timeline": "^6.1.20",
- "@fullcalendar/resource-timegrid": "^6.1.20"
}
} 2) Install the @fullcalendar/web-component-scheduler package:
npm install --save @fullcalendar/web-component-scheduler@beta 3) In your JS, change your imports:
import resourcePlugin
- from '@fullcalendar/resource'
+ from '@fullcalendar/web-component-scheduler'
import adaptivePlugin
- from '@fullcalendar/adaptive'
+ from '@fullcalendar/web-component-scheduler/adaptive'
import scrollGridPlugin
- from '@fullcalendar/scrollgrid'
+ from '@fullcalendar/web-component-scheduler/scrollgrid'
import timelinePlugin
- from '@fullcalendar/timeline'
+ from '@fullcalendar/web-component-scheduler/timeline'
import resourceTimelinePlugin
- from '@fullcalendar/resource-timeline'
+ from '@fullcalendar/web-component-scheduler/resource-timeline'
import resourceTimeGridPlugin
- from '@fullcalendar/resource-timegrid'
+ from '@fullcalendar/web-component-scheduler/resource-timegrid' Breaking: FullCalendar no longer bundles its own CSS. Furthermore, the calendar “theme” has been pulled out from the core, as a plugin. Thus, you must import your own stylesheets. This depends on what theme you choose (see themes.fullcalendar.io):
import '@fullcalendar/web-component/global'
+ import themePlugin from '@fullcalendar/web-component/themes/classic'
// import other plugins...
// stylesheets
+ import '@fullcalendar/web-component/skeleton.styles'
+ import '@fullcalendar/web-component/themes/classic/theme.styles'
+ import '@fullcalendar/web-component/themes/classic/palette.css'
const fullCalendarElement = document.querySelector('full-calendar')
fullCalendarElement.options = {
plugins: [
+ themePlugin,
// other plugins here...
]
} <!-- HTML -->
<full-calendar></full-calendar> Global Script Tags
Breaking: index.global.js renamed to all.global.js (which contains “all” standard plugins), and additional scripts/stylesheets must be added for the theme:
<!-- STANDARD JS -->
- <script src='https://cdn.jsdelivr.net/npm/@fullcalendar/core@6.1.20/index.global.js'></script>
- <script src='https://cdn.jsdelivr.net/npm/@fullcalendar/web-component@6.1.20/index.global.js'></script>
+ <script src='https://cdn.jsdelivr.net/npm/@fullcalendar/web-component@7.0.0-beta.7/all.global.js'></script>
<!-- THEME JS -->
+ <script src='https://cdn.jsdelivr.net/npm/@fullcalendar/web-component@7.0.0-beta.7/themes/classic/global.js'></script>
<!-- STYLESHEETS -->
+ <script src='https://cdn.jsdelivr.net/npm/@fullcalendar/web-component@7.0.0-beta.7/skeleton.styles.js'></script>
+ <script src='https://cdn.jsdelivr.net/npm/@fullcalendar/web-component@7.0.0-beta.7/themes/classic/theme.styles.js'></script>
+ <link href='https://cdn.jsdelivr.net/npm/@fullcalendar/web-component@7.0.0-beta.7/themes/classic/palette.css' rel='stylesheet' /> Please note, skeleton.styles.js and theme.styles.js are <script> tags, and yes they do inject CSS. This is required for the web component’s shadow DOM.
Breaking: Similar breaking changes for scheduler, but with an additional one: scheduler’s JS file no longer contains the standard plugins, so both standard and premium all.global.js files must be included:
<!-- STANDARD + SCHEDULER JS -->
- <script src='https://cdn.jsdelivr.net/npm/@fullcalendar/web-component-scheduler@6.1.20/index.global.js'></script>
+ <script src='https://cdn.jsdelivr.net/npm/@fullcalendar/web-component@7.0.0-beta.7/all.global.js'></script>
+ <script src='https://cdn.jsdelivr.net/npm/@fullcalendar/web-component-scheduler@7.0.0-beta.7/all.global.js'></script>
<!-- THEME JS -->
+ <script src='https://cdn.jsdelivr.net/npm/@fullcalendar/web-component@7.0.0-beta.7/themes/classic/global.js'></script>
<!-- STYLESHEETS -->
+ <script src='https://cdn.jsdelivr.net/npm/@fullcalendar/web-component@7.0.0-beta.7/skeleton.styles.js'></script>
+ <script src='https://cdn.jsdelivr.net/npm/@fullcalendar/web-component@7.0.0-beta.7/themes/classic/theme.styles.js'></script>
+ <link href='https://cdn.jsdelivr.net/npm/@fullcalendar/web-component@7.0.0-beta.7/themes/classic/palette.css' rel='stylesheet' /> Toolbar
Breaking: customButtons renamed to buttons (used for custom and standard buttons). buttonText removed in favor of buttons[].text:
<FullCalendar
- buttonText={{
- hello: 'Hello'
- }}
- customButtons={{
+ buttons={{
hello: {
+ text: 'Hello'
click() {
alert('hello!')
}
}
}}
/> Breaking: buttonIcons removed. Attach a custom class-name and associated glyphicon with buttons[].iconClass:
<FullCalendar
- buttonIcons={{
- next: 'my-button-icon'
- }}
+ buttons={{
+ next: {
+ iconClass: 'my-button-icon'
+ }
+ }}
/> However, SVGs are now preferred over glyphicons, and can be attached with buttons[].iconContent (more info).
Type change: each entry of the buttons map:
- import { type CustomButtonInput } from '@fullcalendar/core'
+ import { type ButtonInput } from '@fullcalendar/react' // or angular/vue3/etc Events (General)
The changes here apply to events in all views.
Breaking: All class-name properties have been renamed and only accept simple string:
<FullCalendar
// calendar-wide
- eventClassNames={['my-event', 'my-util']}
+ eventClass='my-event my-util'
// event-specific
events={[
title: 'My Event',
start: '2026-02-02',
- classNames: ['my-event', 'my-util']
+ className: 'my-event my-util'
]}
// by event-source
eventSources={[
{
url: '/my-feed.php',
- classNames: ['my-event', 'my-util']
+ className: 'my-event my-util'
}
]}
// by resource
resources={[
{
id: 'a',
- eventClassNames: ['my-event', 'my-util']
+ eventClass: 'my-event my-util'
}
]}
/>
// via Event API
const event = calendarApi.getEventById('a')
- event.classNames // array of strings
+ event.className // string
// via Resource API
const resource = calendarApi.getResourceById('b')
- resource.eventClassNames // array of string
+ resource.eventClass // string Breaking: In v6, event color customization would affect literal parts of the element (border, background, text). In v7, the properties are more semantic and the individual theme can decide what to do with them.
<FullCalendar
// calendar-wide
- eventBackgroundColor='red' // these can no longer be set separately...
- eventBorderColor='red' // ...use eventColor instead...
eventColor='red'
- eventTextColor='white'
+ eventContrastColor='white'
// event-specific
events={[
{
title: 'My Event',
start: '2026-02-02',
- backgroundColor: 'red',
- borderColor: 'red',
color: 'red',
- textColor: 'white',
+ contrastColor: 'white',
}
]}
// by event-source
eventSources={[
{
url: '/my-feed.php',
- backgroundColor: 'red',
- borderColor: 'red',
color: 'red',
- textColor: 'white',
+ contrastColor: 'white',
}
]}
// by resource
resources={[
{
id: 'a',
- eventBackgroundColor: 'red',
- eventBorderColor: 'red',
eventColor: 'red',
- eventTextColor: 'white',
+ eventContrastColor: 'white',
}
]}
/>
// via Event API
const event = calendarApi.getEventById('a')
- event.backgroundColor
- event.borderColor
+ event.color
- event.textColor
+ event.contrastColor
// via Resource API
const resource = calendarApi.getResourceById('b')
- resource.eventBackgroundColor
- resource.eventBorderColor
+ resource.eventColor
- resource.eventTextColor
+ resource.eventContrastColor If you’ve customized the classic theme to have events with border colors that are DIFFERENT than their background colors, and want to maintain that look in v7, you’ll need to fork the theme.
Breaking: In v6, for list-item events in DayGrid view, the content generated eventContent would clear rendering of the colored dot. In v7, eventContent injects into the “inner” container (aka eventInnerClass) which does not wrap the dot (aka eventBeforeClass). To restore old behavior:
<FullCalendar
eventContent={(arg) => <span>Cool {arg.event.title}</span>}
views={{
+ dayGrid: { listItemEventBeforeClass: 'display-none' },
+ timeGrid: { listItemEventBeforeClass: 'display-none' }
}}
/>
/* in CSS */
+ .display-none { display: none } Type change: The parameter passed to eventClass (formerly eventClassNames), eventContent, eventDidMount, and eventWillUnmount has changed:
- import { type EventContentArg } from '@fullcalendar/core'
+ import { type EventDisplayData } from '@fullcalendar/react' // or angular/vue3/etc Breaking: Event API’s .toPlainObject() and .toJSON() methods have modified signatures and return types:
const res = event.toPlainObject({ // or .toJSON()
- collapseColor: true
})
- res.classNames // array of strings
+ res.className // string
- res.backgroundColor
- res.borderColor
+ res.color
- res.textColor
+ res.contrastColor Resources (General)
Breaking: The generic resourceLabel* settings have been replaced with more UI-specific settings. Class-name settings now use simple strings instead of arrays:
- Resource Day Header for Resource DayGrid and Resource TimeGrid views
- Resource Cell for Resource Timeline view
Breaking: Resource API’s .toPlainObject() and .toJSON() methods have modified signatures and return types:
const res = event.toPlainObject({ // or .toJSON()
- collapseColor: true
})
- res.eventClassNames // array of strings
+ res.eventClass // string
- res.eventBackgroundColor
- res.eventBorderColor
+ res.eventColor
- res.eventTextColor
+ res.eventContrastColor Calendar Views (General)
The follow changes apply to all calendar views.
Root Element
Breaking: viewClassNames renamed and accepts only a simple string:
<FullCalendar
- viewClassNames={['my-view', 'my-util']}
+ viewClass='my-view my-util'
/> Types change: The parameter given to all view* callbacks has changed:
- import { type ViewContentArg } from '@fullcalendar/core'
+ import { type ViewDisplayData } from '@fullcalendar/react' // or angular/vue3/etc Nav-Links
Breaking: navLinkClassNames rename and accepts only a simple string:
<FullCalendar
- navLinkClassNames={['my-nav-link', 'my-util']}
+ navLinkClass='my-nav-link my-util'
/> More-Links
Breaking: moreLinkClassNames rename and accepts only a simple string:
<FullCalendar
- moreLinkClassNames={['my-more-link', 'my-util']}
+ moreLinkClass='my-more-link my-util'
/> Types change: The parameter given to all moreLink* callbacks has changed:
- import { type MoreLinkContentArg } from '@fullcalendar/core'
+ import { type MoreLinkData } from '@fullcalendar/react' // or angular/vue3/etc Week Number
Breaking: The generic weekNumber* settings have been replaced with more UI-specific settings. Class-name settings now use simple strings instead of arrays:
- Inline Week Number for DayGrid view
- Week Number Header for TimeGrid view
All-Day
Breaking: The generic allDay* settings have been replaced with more UI-specific settings. Class-name settings now use simple strings instead of arrays:
- All-Day Header for TimeGrid view
- All-Day Text on Events for List view
Time Slot Header
Time slots are present in TimeGrid View and Timeline View. The changes here apply to both views.
Breaking: slot “label” settings have been renamed to slot “header”. Also, class-names must be simple strings:
<FullCalendar
- slotLabelClassNames={['my-slot', 'my-util']}
+ slotHeaderClass='my-slot my-util'
- slotLabelContent={(data) => <span>{data.text}</span>}
+ slotHeaderContent={(data) => <span>{data.text}</span>}
- slotLabelDidMount={(data) => { /* handler */ }}
+ slotHeaderDidMount={(data) => { /* handler */ }}
- slotLabelWillUnmount={(data) => { /* handler */ }}
+ slotHeaderWillUnmount={(data) => { /* handler */ }}
/> Type change: The parameter given to the callbacks has changed:
- import { type SlotLabelContentArg } from '@fullcalendar/core'
+ import { type SlotHeaderData } from '@fullcalendar/react' // or angular/vue3/etc Time Slot Lane
Time slots are present in TimeGrid View and Timeline View. The changes here apply to both views.
Breaking: the slotLaneClassNames setting renamed. Must be a simple string. slotLaneContent removed:
<FullCalendar
- slotLaneClassNames={['my-slot', 'my-util']}
+ slotLaneClass='my-slot my-util'
// NO REPLACEMENT - lane inner-content can no longer be customized
- slotLaneContent={(data) => <span>...</span>}
/> Type change: The parameter given to the slotLane* callbacks has changed:
- import { type SlotLaneContentArg } from '@fullcalendar/core'
+ import { type SlotLaneData } from '@fullcalendar/react' // or angular/vue3/etc Now-Indicator
A now-indicator is present in TimeGrid View and Timeline View. The changes here apply to both views.
Breaking: in v6, the nowIndicator* settings represented BOTH the “arrow”, which appeared in the time axis, and the “line”, which appeared over a day. One would differentiate based on data.isAxis (now removed). In v7, there are distinct settings for each:
<FullCalendar
- nowIndicatorClassNames={(data) => (
- data.isAxis
- ? ['my-arrow', 'my-util']
- : ['my-line', 'my-util']
- )}
- nowIndicatorContent={(data) => (
- data.isAxis
- ? <span>the axis content</span>
- : <span>the line content</span>
- )}
- nowIndicatorDidMount={(data) => {
- if (data.isAxis) {
- // for axis
- } else {
- // for line
- }
- }}
- nowIndicatorWillUnmount={(data) => {
- if (data.isAxis) {
- // for axis
- } else {
- // for line
- }
- }}
/><FullCalendar
+ nowIndicatorHeaderClass='my-arrow my-util'
+ nowIndicatorLineClass='my-line my-util'
+ nowIndicatorHeaderContent={(data) => (
+ <span>the axis content</span>
+ )}
+ nowIndicatorLineContent={(data) => (
+ <span>the line content</span>
+ )}
+ nowIndicatorHeaderDidMount={(data) => {
+ // for axis
+ }}
+ nowIndicatorLineDidMount={(data) => {
+ // for line
+ }}
+ nowIndicatorHeaderWillUnmount={(data) => {
+ // for axis
+ }}
+ nowIndicatorLineWillUnmount={(data) => {
+ // for line
+ }}
/>Type changes: The parameter given to the callbacks has also been split in two:
- import { NowIndicatorContentArg } from '@fullcalendar/core'
// for axis
+ import { NowIndicatorHeaderData } from '@fullcalendar/react' // or angular/vue3/etc
// for line
+ import { NowIndicatorLineData } from '@fullcalendar/react' // or angular/vue3/etc DayGrid View
Includes changes from:
Day Header
Breaking: dayHeaderClassNames renamed and accepts only a simple string. Can no longer do horizontal alignment:
<FullCalendar
- dayHeaderClassNames={['my-header', 'my-util']}
+ dayHeaderClass='my-header my-util'
+ dayHeaderAlign='start' // horizontal alignment (in LTR, 'start' means left)
/>
/* in CSS */
.my-header {
- text-align: left; /* horizontal alignment */
} The dayHeader* settings now apply to the popover header, which is usually desirable. See Popover CSS migration docs.
Types change: The parameter given to all dayHeader* callbacks has changed:
- import { type DayHeaderContentArg } from '@fullcalendar/core'
+ import { type DayHeaderData } from '@fullcalendar/react' // or angular/vue3/etc Day Cell
Breaking: dayCellClassNames renamed and accepts only a simple string. dayCellContent renamed:
<FullCalendar
- dayCellClassNames={['my-cell', 'my-util']}
+ dayCellClass='my-cell my-util'
- dayCellContent={(data) => (
+ dayCellTopContent={(data) => (
<span>In place of day-number</span>
)}
/> The dayCell* settings now apply to the popover body, which is usually desirable. See Popover CSS migration docs.
The dayCell* settings previously applied to TimeGrid Day Lane, but no longer.
Types change: The parameter given to all dayCell* callbacks has changed:
- import { type DayCellContentArg } from '@fullcalendar/core'
+ import { type DayCellData } from '@fullcalendar/react' // or angular/vue3/etc Inline Week Number
Breaking: Week numbers, as they render in a DayGrid, are now called “inline week numbers” because they rest within the cells, not as a separate column. Thus, they have been renamed. You can configure them as top-level settings, and class-name settings must be simple strings:
<FullCalendar
- views={{
- dayGrid: {
- weekNumberClassNames: ['my-week-number', 'my-util']
- weekNumberContent: (data) => <span>{data.text}</span>
- weekNumberDidMount: (data) => { /* handler */ }
- weekNumberWillUnmount: (data) => { /* handler */ }
- }
- }}
+ inlineWeekNumberClass='my-week-number my-util'
+ inlineWeekNumberContent={(data) => <span>{data.text}</span>}
+ inlineWeekNumberDidMount={(data) => { /* handler */ }}
+ inlineWeekNumberWillUnmount={(data) => { /* handler */ }}
/> Type change: The parameter given to these callbacks has changed:
- import { type WeekNumberContentArg } from '@fullcalendar/core'
+ import { type InlineWeekNumberData } from '@fullcalendar/react' // or angular/vue3/etc Resource DayGrid View
Includes changes from:
Resource Day Header
Breaking: “Resource labels”, as they render in DayGrid and TimeGrid, are now called “resource day headers”. You can configure them as top-level settings, and class-name settings must be simple strings:
<FullCalendar
- views={{
- resourceDayGrid: { // OR resourceTimeGrid
- resourceLabelClassNames: ['my-header', 'my-util'],
- resourceLabelContent: (data) => <span>{data.text}</span>,
- resourceLabelDidMount: (data) => { /* handler */ },
- resourceLabelWillUnmount: (data) => { /* handler */ },
- }
- }}
+ resourceDayHeaderClass='my-header my-util'
+ resourceDayHeaderAlign='start' // horizontal alignment (in LTR, 'start' means left)
+ resourceDayHeaderContent={(data) => <span>{data.text}</span>}
+ resourceDayHeaderDidMount={(data) => { /* handler */ }}
+ resourceDayHeaderWillUnmount={(data) => { /* handler */ }}
/>
/* in CSS */
.my-header {
- text-align: left; /* horizontal alignment */
} Type change: The parameter given to these callbacks has changed:
- import { type ResourceLabelContentArg } from '@fullcalendar/core'
+ import { type ResourceDayHeaderData } from '@fullcalendar/react' // or angular/vue3/etc TimeGrid View
Includes changes from:
- Calendar Views (General)
- Events (General)
- DayGrid View - for “day headers” and all-day “day cells”
Week Number Header
Breaking: Week numbers, as they render in a TimeGrid, are now called “week number headers” because they’re located in the header of the view, above the time axis. They have been renamed and can be configured as top-level settings, and class-name settings must be simple strings:
<FullCalendar
- views={{
- timeGrid: {
- weekNumberClassNames: ['my-week-header', 'my-util']
- weekNumberContent: (data) => <span>{data.text}</span>
- weekNumberDidMount: (data) => { /* handler */ }
- weekNumberWillUnmount: (data) => { /* handler */ }
- }
- }}
+ weekNumberHeaderClass='my-week-header my-util'
+ weekNumberHeaderContent={(data) => <span>{data.text}</span>}
+ weekNumberHeaderDidMount={(data) => { /* handler */ }}
+ weekNumberHeaderWillUnmount={(data) => { /* handler */ }}
/> Type change: The parameter given to these callbacks has changed:
- import { type WeekNumberContentArg } from '@fullcalendar/core'
+ import { type WeekNumberHeaderData } from '@fullcalendar/react' // or angular/vue3/etc All-Day Header
Breaking: The cell labeling the all-day section has been renamed to “all day header”. Class-name settings must be simple strings:
<FullCalendar
- views={{
- timeGrid: {
- allDayClassNames: ['my-all-day', 'my-util'],
- allDayContent: (data) => <span>{data.text}</span>,
- allDayDidMount: (data) => { /* handler */ },
- allDayWillUnmount: (data) => { /* handler */ },
- }
- }}
+ allDayHeaderClass='my-all-day my-util'
+ allDayHeaderContent={(data) => <span>{data.text}</span>}
+ allDayHeaderDidMount={(data) => { /* handler */ }}
+ allDayHeaderWillUnmount={(data) => { /* handler */ }}
/> Type change: The parameter given to these callbacks has changed:
- import { type AllDayContentArg } from '@fullcalendar/core'
+ import { type AllDayHeaderData } from '@fullcalendar/react' // or angular/vue3/etc Day Lane
Breaking: TimeGrid lane hooks are renamed from dayCell* to dayLane*, lane class-name settings must be simple strings, and lane content customization is no longer supported.
<FullCalendar
- dayCellClassNames={['my-lane', 'my-util']}
+ dayLaneClass='my-lane my-util'
// NO REPLACEMENT - can't customize content in here anymore
- dayCellContent={(data) => <span>...</span>}
- dayCellDidMount={(data) => { /* handler */ }}
+ dayLaneDidMount={(data) => { /* handler */ }}
- dayCellWillUnmount={(data) => { /* handler */ }}
+ dayLaneWillUnmount={(data) => { /* handler */ }}
/> Type change: The parameter given to these callbacks has changed:
- import { type DayCellContentArg } from '@fullcalendar/core'
+ import { type DayLaneData } from '@fullcalendar/react' // or angular/vue3/etc Resource TimeGrid View
Includes changes from:
- Calendar Views (General)
- Events (General)
- TimeGrid View
- DayGrid View - for “day headers” and all-day “day cells”
List View
Includes changes from:
Day Header
Breaking: List-view day header hooks moved from views.list.dayHeader* to top-level listDayHeader* settings, and class-name settings must be simple strings.
<FullCalendar
- views={{
- list: {
- dayHeaderClassNames: ['my-header', 'my-util'],
- dayHeaderContent: (data) => <span>{data.text}</span>,
- dayHeaderDidMount: (data) => { /* handler */ },
- dayHeaderWillUnmount: (data) => { /* handler */ },
- }
- }}
+ listDayHeaderClass='my-header my-util'
+ listDayHeaderContent={(data) => <span>{data.text}</span>} // uses ListDayHeaderInnerData
+ listDayHeaderDidMount={(data) => { /* handler */ }}
+ listDayHeaderWillUnmount={(data) => { /* handler */ }}
/> Type change: The parameter given to these callbacks has changed:
- import { type DayHeaderContentArg } from '@fullcalendar/core'
// for listDayHeaderClass, listDayHeaderDidMount, listDayHeaderWillUnmount
+ import { type ListDayHeaderData } from '@fullcalendar/react' // or angular/vue3/etc
// for listDayHeaderContent, listDayHeaderInnerClass (new)
+ import { type ListDayHeaderInnerData } from '@fullcalendar/react' // or angular/vue3/etc All-Day Text on Events
Breaking: In List view, all-day event text is no longer customized via generic allDay* hooks. Use list event* hooks instead.
<FullCalendar
- allDayClassNames={['my-all-day-text', 'my-util']}
- allDayContent={(data) => <span>{data.text}</span>}
- allDayDidMount={(data) => { /* handler */ }}
- allDayWillUnmount={(data) => { /* handler */ }}
+ views={{
+ list: {
+ eventTimeClass: 'my-all-day-text my-util',
+ eventContent: (data) => (
+ <>
+ <div className={data.timeClass}><i>{data.timeText}</i></div>
+ <div className={data.titleClass}>{data.titleText}</div>
+ </>
+ ),
+ eventDidMount: (data) => {
+ data.el.querySelector('.my-all-day-text')
+ },
+ eventWillUnmount: (data) => {
+ data.el.querySelector('.my-all-day-text')
+ }
+ }
+ }}
/> No-Events Screen
Breaking: noEventsClassNames has been renamed to noEventsClass, which accepts only a simple string.
<FullCalendar
- noEventsClassNames={['my-no-events', 'my-util']}
+ noEventsClass='my-no-events my-util'
/> Type change: The parameter given to these callbacks has changed:
- import { type NoEventsContentArg } from '@fullcalendar/core'
+ import { type NoEventsData } from '@fullcalendar/react' // or angular/vue3/etc MultiMonth View
Includes changes from:
Breaking: multiMonthMinWidth and multiMonthTitleFormat are renamed to singleMonthMinWidth and singleMonthTitleFormat.
<FullCalendar
- multiMonthMinWidth={200}
+ singleMonthMinWidth={200}
- multiMonthTitleFormat={{ year: 'numeric', month: 'long' }}
+ singleMonthTitleFormat={{ year: 'numeric', month: 'long' }}
/> Breaking: singleMonthMinWidth (formerly multiMonthMinWidth) now INCLUDES padding.
Resource Timeline View
Includes changes from:
Breaking: resourceAreaColumns is renamed to resourceColumns, and related *ClassNames hooks are now *Class string settings.
<FullCalendar
- resourceAreaColumns={[
+ resourceColumns={[
{
id: 'resource-a',
title: 'Resource A',
- headerClassNames: ['my-header', 'my-util'],
+ headerClass: 'my-header my-util',
- cellClassNames: ['my-cell', 'my-util'],
+ cellClass: 'my-cell my-util',
}
]}
// will apply to ALL headers
- resourceAreaHeaderClassNames={['my-header', 'my-util']}
+ resourceColumnHeaderClass='my-header my-util'
- resourceAreaHeaderContent={(data) => <span>custom content</span>}
+ resourceColumnHeaderContent={(data) => <span>custom content</span>}
- resourceAreaHeaderDidMount={() => { /* handler */ }}
+ resourceColumnHeaderDidMount={() => { /* handler */ }}
- resourceAreaHeaderWillUnmount={() => { /* handler */ }}
+ resourceColumnHeaderWillUnmount={() => { /* handler */ }}
/> Type change: The parameter given to these callbacks has changed:
- import { type ColHeaderContentArg } from '@fullcalendar/core'
+ import { type ResourceColumnHeaderData } from '@fullcalendar/react' // or angular/vue3/etc Breaking: In v6, the resourceGroupLabel* settings where used to style both row-grouping group headers AS WELL AS column-grouping cells, without any way to distinguish the two from the callbacks themselves. In v7, there are two separate entities for each (resourceGroupHeader* and the generic resourceCell*). Also, .groupValue is killed:
<FullCalendar
- resourceGroupLabelClassNames={['my-resource-group-header', 'my-resource-group-cell', 'my-util']}
- resourceGroupLabelContent={(data) => (
- <span>{data.groupValue}</span>
- )}
- resourceGroupLabelDidMount={(data) => { /* handler */ }}
- resourceGroupLabelWillUnmount={(data) => { /* handler */ }}
// header for grouped rows
+ resourceGroupHeaderClass='my-resource-group-header my-util'
+ resourceGroupHeaderContent={(data) => (
+ <span>{data.fieldValue}</span>
+ )}
+ resourceGroupHeaderDidMount={(data) => { /* handler */ }}
+ resourceGroupHeaderWillUnmount={(data) => { /* handler */ }}
// grouped cells
+ resourceCellClass={(data) => clsx(
+ !data.resource && // in group?
+ 'my-resource-group-cell my-util'
+ )}
+ resourceCellContent={(data) => (
+ <span>{data.fieldValue}</span> // applies to all cells (grouped and non-grouped)
+ )}
+ resourceCellDidMount={(data) => {
+ if (!data.resource) { /* handler for group */ }
+ }}
+ resourceCellWillUnmount={(data) => {
+ if (!data.resource) { /* handler for group */ }
+ }}
/> Type change: The parameter given to these callbacks has changed:
- import { type ColCellContentArg } from '@fullcalendar/core'
// header for grouped rows
+ import { type ResourceGroupHeaderData } from '@fullcalendar/react' // or angular/vue3/etc
// grouped cells
+ import { type ResourceCellData } from '@fullcalendar/react' // or angular/vue3/etc Resource Cell
Breaking: resourceLabel* has been replaced by generalized resourceCell* hooks. If you only want the title cell, branch on data.field === 'title'.
<FullCalendar
- views={{
- resourceTimeline: {
- resourceLabelClassNames: ['my-resource-cell', 'my-util'],
- resourceLabelContent: (data) => (
- <span>{data.resource.title}</span>
- ),
- resourceLabelDidMount: (data) => { /* handler */ },
- resourceLabelWillUnmount: (data) => { /* handler */ },
- }
- }}
+ resourceCellClass={(data) => clsx(
+ (data.field === 'title') && 'my-resource-cell my-util'
+ )}
+ resourceCellContent={(data) => (
+ <span>{data.fieldValue}</span> // applies to all cells
+ )}
+ resourceCellDidMount={(data) => {
+ if (data.field === 'title') { /* handler */ }
+ }}
+ resourceCellWillUnmount={(data) => {
+ if (data.field === 'title') { /* handler */ }
+ }}
/> Note that the resourceLabel* props ALSO apply to Resource DayGrid/TimeGrid. See those migrations above.
Resource Lane
Breaking: resourceLaneClassNames is renamed to resourceLaneClass (simple string only), and resourceLaneContent is split into resourceLaneTopContent and resourceLaneBottomContent.
<FullCalendar
- resourceLaneClassNames={['my-lane', 'my-util']}
+ resourceLaneClass='my-lane my-util'
- resourceLaneContent={(data) => <span>...</span>}
+ resourceLaneTopContent={(data) => <span>...</span>}
+ // or
+ resourceLaneBottomContent={(data) => <span>...</span>}
/> Type change: The parameter given to these callbacks has changed:
- import { type ResourceLaneContentArg } from '@fullcalendar/core'
+ import { type ResourceLaneData } from '@fullcalendar/react' // or angular/vue3/etc Group Lane
Breaking: resourceGroupLaneClassNames is renamed to resourceGroupLaneClass (simple string only), and group data now uses fieldValue instead of groupValue.
<FullCalendar
- resourceGroupLaneClassNames={['my-group-lane', 'my-util']}
+ resourceGroupLaneClass='my-group-lane my-util'
resourceGroupContent={(data) => (
- <span>{data.groupValue}</span>
+ <span>{data.fieldValue}</span>
)}
/> Type change: The parameter given to these callbacks has changed:
- import { type ColCellContentArg } from '@fullcalendar/core'
+ import { type ResourceGroupLaneData } from '@fullcalendar/react' // or angular/vue3/etc Custom Views
Custom View via Settings
Breaking: In custom view definitions, .classNames (array) is replaced by .class / .className (single string).
var calendar = new Calendar(calendarEl, {
views: {
timeGridFourDay: {
- classNames: ['my-classname', 'my-util'],
+ className: 'my-classname my-util',
type: 'timeGrid',
duration: { days: 4 },
}
}
}) Breaking: The buttonText setting no longer respected. Instead, add to the buttons map:
var calendar = new Calendar(calendarEl, {
views: {
timeGridFourDay: {
type: 'timeGrid',
duration: { days: 4 },
- buttonText: '4 day'
}
},
+ buttons: {
+ timeGridFourDay: {
+ text: '4 day'
+ }
+ },
headerToolbar: {
center: 'dayGridMonth,timeGridFourDay'
}
}) Custom View via JS
Breaking: createPlugin is no longer required for custom view plugin objects (see “Custom Plugins” below).
Luxon Plugin
Breaking: The @fullcalendar/luxon3 plugin has been removed. Remove it from your package.json:
{
"dependencies": {
"@fullcalendar/react": "7@beta",
- "@fullcalendar/luxon3": "^6.1.20",
"luxon": "^3.7.2"
}
} Breaking: Because the @fullcalendar/luxon3 plugin has been removed, the toLuxonDateTime and toLuxonDuration utilities are no longer available. You can easily replace with direct calls to Luxon:
- import { toLuxonDateTime, toLuxonDuration } from '@fullcalendar/luxon3'
+ import { DateTime, Duration } from 'luxon'
const locale = 'en-US'
const timeZone = 'America/New_York'
<FullCalendar
locale={locale}
timeZone={timeZone}
dateClick={(arg) => {
- const dt = toLuxonDateTime(arg.date, arg.view.calendar)
+ const dt = DateTime.fromJSDate(arg.date, { zone: timeZone, locale })
...
}}
eventDrop={(arg) => {
- const dur = toLuxonDuration(arg.delta, arg.view.calendar)
+ const dur = Duration.fromObject(arg.delta, { locale })
...
}}
/> Breaking: The @fullcalendar/luxon3 plugin has been removed, but it’s format-string functionality has been moved to a different plugin:
npm install --save @fullcalendar/format-luxon3 Then replace usage in your code:
- import luxonPlugin from '@fullcalendar/luxon3'
+ import luxonFormatPlugin from '@fullcalendar/format-luxon3'
<FullCalendar
titleFormat='LLLL d, yyyy' // a format-string
plugins={[
- luxonPlugin,
+ luxonFormatPlugin, // for format-strings only
...
]}
...
/> Moment Plugins
Breaking: The two moment plugin have been removed. Remove them from your package.json:
{
"dependencies": {
"@fullcalendar/react": "7@beta",
- "@fullcalendar/moment": "^6.1.20",
- "@fullcalendar/moment-timezone": "^6.1.20",
"moment": "^2.30.1"
}
} Breaking: Because the @fullcalendar/moment plugin has been removed, the toMoment and toMomentDuration utilities are no longer available. You can replace them with direct calls to Moment:
- import { toMoment, toMomentDuration } from '@fullcalendar/luxon3'
+ import moment from 'moment'
const locale = 'en-US'
const timeZone = 'America/New_York'
<FullCalendar
locale={locale}
timeZone={timeZone}
dateClick={(arg) => {
- const mom = toMoment(arg.date, arg.view.calendar)
+ let mom: moment.Moment
+ if (timeZone === 'local') {
+ mom = moment(arg.date)
+ } else if (timeZone === 'UTC') {
+ mom = moment.utc(arg.date)
+ } else {
+ mom = moment.tz(arg.date, timeZone)
+ }
...
}}
eventDrop={(arg) => {
- const dur = toMomentDuration(arg.delta, arg.view.calendar)
+ const dur = moment.duration(arg.delta)
...
}}
/> Breaking: The @fullcalendar/moment plugin has been removed, but it’s format-string functionality has been moved to a different plugin:
npm install --save @fullcalendar/format-moment Then replace usage in your code:
- import momentPlugin from '@fullcalendar/moment'
+ import momentFormatPlugin from '@fullcalendar/format-moment'
<FullCalendar
titleFormat: 'MMMM D, YYYY' // a format-string
plugins={[
- momentPlugin,
+ momentFormatPlugin, // for format-strings only
...
]}
...
/> Custom Plugins
Breaking: the createPlugin function no longer necessary to prepare a plugin. Just pass-in the object
- const customViewPlugin = createPlugin({
+ const customViewPlugin = {
views: {
custom: CustomViewConfig
}
+ };
- });
let calendar = new Calendar(calendarEl, {
plugins: [customViewPlugin],
}); Type change:
- import { PluginDef, PluginDefInput } from '@fullcalendar/core'
+ import { PluginInput } from '@fullcalendar/react' // or angular/vue3/etc Custom Theme Class
Breaking: V6 had an poorly-documented API for theming that was rarely used by developers. It has been replaced by the miriad of *Class and *Content settings now available in v7. Here’s how to migrate:
- import {
- StandardTheme,
- createPlugin
- } from '@fullcalendar/core'
- class CustomTheme extends StandardTheme {
- root = 'my-root'
// toolbar
- buttonGroup = 'my-button-group'
- button = 'my-button'
- buttonActive = 'my-button-selected'
// popover
- popover='my-popover'
- popoverHeader='my-popover-header'
- popoverContent='my-popover-body'
// affects multiple elements
- tableCellShaded = 'my-cell-shaded'
- }
<FullCalendar
- plugins={
- createPlugin({ custom: CustomTheme })
- ]}
- theme='custom' <FullCalendar
+ className='my-root'
// toolbar
+ buttonGroupClass='my-button-group'
+ buttonClass={(data) => clsx(
+ 'my-button',
+ data.isSelected && 'my-button-selected',
+ )}
// popover
+ popoverClass='my-popover'
+ dayHeaderClass={(data) => clsx(
+ data.inPopover && 'my-popover-header'
+ )}
+ dayCellClass={(data) => clsx(
+ data.inPopover && 'my-popover-body'
+ )}
// affects multiple elements
+ allDayDividerClass='my-cell-shaded'
+ listDayHeaderClass='my-cell-shaded'
+ resourceColumnDividerClass='my-cell-shaded'
+ resourceGroupHeaderClass='my-cell-shaded'
+ resourceGroupLaneClass='my-cell-shaded'
/>The following members have been removed because class-based glyph icons are now discouraged:
- CustomTheme.prototype.baseIconClass
- CustomTheme.prototype.iconClasses
- CustomTheme.prototype.rtlIconClasses
- CustomTheme.prototype.iconOverridePrefix Locales
Breaking: The Shape of a locale object has changed:
{
code: 'es',
- buttonText: {
- prev: 'Ant',
- next: 'Sig',
- today: 'Hoy',
- year: 'Año',
- month: 'Mes',
- week: 'Semana',
- day: 'Día',
- list: 'Agenda',
- },
- buttonHints: {
- prev: '$0 antes',
- next: '$0 siguiente',
- today: (unitText) => { /* ... */ }
- },
} {
code: 'es',
+ prevText: 'Ant',
+ nextText: 'Sig',
+ todayText: 'Hoy',
+ yearText: 'Año',
+ monthText: 'Mes',
+ weekText: 'Semana',
+ dayText: 'Día',
+ listText: 'Agenda',
+ prevHint: '$0 antes',
+ nextHint: '$0 siguiente',
+ todayHint: (unitText) => { /* ... */ }
}Interactions
Breaking: removed fixedMirrorParent setting. Element dragging “mirror” elements will always be attached to <body> now:
<FullCalendar
- fixedMirrorParent={document.body} // unnecessary now
/> Type change: For all names, the Arg postfix replaced with Data:
- import {
- DateSelectArg,
- DateUnselectArg,
- EventClickArg,
- EventAddArg,
- EventChangeArg,
- EventRemoveArg,
- } from '@fullcalendar/core'
- import {
- DateClickArg,
- EventDragStartArg,
- EventDragStopArg,
- EventDropArg,
- EventResizeStartArg,
- EventResizeStopArg,
- EventResizeDoneArg,
- EventHoveringArg,
- DropArg,
- EventReceiveArg,
- EventLeaveArg,
- } from '@fullcalendar/interaction'+ import {
+ DateSelectData,
+ DateUnselectData,
+ EventClickData,
+ EventAddData,
+ EventChangeData,
+ EventRemoveData,
+ } from '@fullcalendar/react'
// or angular/vue3/etc
+ import {
+ DateClickData,
+ EventDragStartData,
+ EventDragStopData,
+ EventDropData,
+ EventResizeStartData,
+ EventResizeStopData,
+ EventResizeDoneData,
+ EventHoveringData,
+ DropData,
+ EventReceiveData,
+ EventLeaveData,
+ } from '@fullcalendar/react/interaction'
// or angular/vue3/etcMisc
Type change: The argument given to the datesSet callback has changed:
- import { DatesSetArg } from '@fullcalendar/core'
+ import { DatesSetData } from '@fullcalendar/react' // or angular/vue3/etc