---
title: "FullCalendarとは？v7.1.2の導入・使い方・日本語化・カスタマイズとv6からの移行を解説"
url: "https://www.issoh.co.jp/tech/details/4742/"
published: 2025-01-08
updated: 2026-10-14
categories: ["JavaScript"]
publisher: "株式会社一創"
---

# FullCalendarとは？v7.1.2の導入・使い方・日本語化・カスタマイズとv6からの移行を解説

FullCalendarは、月・週・日・リスト表示とドラッグ＆ドロップによる予定変更を備えた、JavaScriptのイベントカレンダーライブラリです。2026年6月にv7.0.0が出てから、9月5日に7.1.0、10月6日に7.1.1、10月12日に7.1.2と更新が続き、`npm install fullcalendar` で入るのはv7になりました。v7はパッケージ構成、CSSの読み込み方、見た目を変える設定の名前がまとめて変わったため、v6以前の解説記事のコードやCSSはそのままでは動きません。この記事では、v7.1.2を実際にnpmで入れて動かした結果をもとに、導入、日本語化、土日の色分けやテーマなどのカスタマイズ、データベース連携、無料で使える範囲と商用ライセンスを順に解説します。

## まとめ：FullCalendar v7.1.2を使う前に押さえる要点

- 現行版は7.1.2（2026年10月12日）。本体は `fullcalendar` パッケージ1つで、月表示などのプラグインは `fullcalendar/daygrid` のようなサブパスから読み込みます
- CSSは自動で注入されません。`skeleton.css`・テーマの `theme.css`・配色のパレットCSSの3枚を自分で読み込み、`temporal-polyfill` も一緒にインストールします
- v7の描画結果はクラス名が短い記号になり、v6向けに書かれた `.fc-day-sat` のようなCSSは当たりません。土日の色分けは `dayCellClass` で自分のクラスを付けて行います
- 標準機能はMITライセンスで商用利用も無料です。タイムライン表示やリソース表示はPremiumで、非公開の商用システムでは480ドルからの有償ライセンスが必要です
- v6の記事どおり `@fullcalendar/daygrid` を入れるとv6.1.21が入り、v7本体と混ざって動きません

## FullCalendarの概要と現行版7.1.2の位置づけ

FullCalendarはAdam Shaw氏が開発するオープンソースのカレンダーUIで、公式サイトは [fullcalendar.io](https://fullcalendar.io/)、ソースはGitHubの fullcalendar/fullcalendar で公開されています。予約システム、会議室や設備の空き状況、シフト表、社内のスケジュール共有など、予定を日付の枠に並べてクリックやドラッグで操作する画面を短期間で作る用途で使われます。

v7はテーマの仕組みを作り直したメジャーバージョンで、Monarch・Forma・Breezy・Pulseの4つの新テーマと、v6までの見た目を引き継ぐClassicテーマが入りました。7.1系では細かな修正が続いています。[7.1.1のリリースノート](https://github.com/fullcalendar/fullcalendar/releases/tag/v7.1.1)ではMUI v9への対応と、React 19で `inert` 属性の警告が出る不具合の修正が挙げられています。[7.1.2](https://github.com/fullcalendar/fullcalendar/releases/tag/v7.1.2)はアクセシビリティの修正が中心で、日セル内の予定がスクリーンリーダーで1件ずつ読み上げられるよう、リストの構造に改められました。

| 版      | 公開日        | 主な内容                   |
| ------ | ---------- | ---------------------- |
| 7.1.2  | 2026-10-12 | npmのlatest。アクセシビリティの修正 |
| 7.1.1  | 2026-10-06 | MUI v9対応、React 19の警告修正 |
| 7.1.0  | 2026-09-05 | 月表示の描画量削減（破壊的変更あり）     |
| 7.0.0  | 2026-06-19 | テーマ刷新、パッケージ統合          |
| 6.1.21 | 2026-06-18 | v6系の最新（10月14日時点）       |

7.1.0の破壊的変更は、月表示で `dayMaxEvents: true` を使うと、表示に必要な予定だけをDOMへ挿入するようになった点です。その結果、`eventContent` などの描画フックが一部の予定にしか呼ばれなくなりました。描画フックで全件の集計をしているコードは、`calendar.getEvents()` から数える形に改めてください。

なお、WordPressの「WP FullCalendar」とObsidianの「Full Calendar」は、このライブラリを組み込んだ別の製品です。WP FullCalendarは説明文でFullCalendar 3.xを使うと明記しています。ObsidianのプラグインはFullCalendar 5.x系に依存しており、GitHubのリポジトリは2026年8月1日付でcommunity-archive配下のアーカイブ（読み取り専用）になりました。どちらにもこの記事のv7の手順は当てはまりません。

## 無料で使える範囲と商用利用のライセンス

### 標準機能とPremiumのライセンスの選び方

月・週・日・リスト・複数月の表示、ドラッグ＆ドロップ、日本語化、テーマなど、ドキュメントで「Premium」と印の付いていない機能はすべてMITライセンスです。著作権表示とライセンス文を残せば、社内システムや受託開発、有料のSaaSを含めて無償で使えます。

有償になるのは、横軸に時間を取るタイムライン表示や、会議室・担当者などの「リソース」ごとに列や行を分ける表示です。これらはPremium（パッケージ名は `fullcalendar-scheduler`）に含まれ、[公式のライセンスページ](https://fullcalendar.io/license)が定める3つから選びます。

| 利用形態               | 選ぶライセンス            | schedulerLicenseKey                            |
| ------------------ | ------------------ | ---------------------------------------------- |
| 非公開・営利（一般的な業務システム） | 商用ライセンス（480ドルから）   | 購入時に発行されるキー                                    |
| 登録非営利団体の非商用利用・評価   | CC BY-NC-ND 4.0    | `CC-Attribution-NonCommercial-NoDerivatives`   |
| ソース公開のプロジェクト       | AGPLv3（v6まではGPLv3） | `AGPL-My-Frontend-And-Backend-Are-Open-Source` |

非商用枠の対象は登録された非営利団体だけで、政府機関や大学は含まれません。もう1つ見落としやすいのが、オープンソース向けの選択肢がGPLv3からAGPLv3に変わった点です。公式は、GPLv3のままだとソースを配布しないSaaSが無償で使えてしまう抜け道があったため、それを塞ぐ目的だと説明しています。AGPLv3はフロントエンドとバックエンドの両方をAGPLv3で公開できる場合に限られるので、非公開の業務システムでPremium機能を使うなら商用ライセンスを買うことになります。

商用ライセンスの価格表示は「Starting at $480」で、席数はPremiumのソース・JavaScript API・CSSに触れる開発者の人数で数えます。有効期限前に更新すれば基本価格の50%引き、期限後なら25%引きで、更新をやめても期限切れ前に出た最終版は使い続けられます。

### Premiumのタイムライン表示を試す最小構成

評価だけなら、CC BY-NC-NDのキーを指定して期間の制限なく試せます（商用の本番環境では使えません）。Vanilla JSでは `fullcalendar-scheduler` を追加し、サブパスからリソースタイムラインのプラグインを読み込みます。

```
npm install fullcalendar@7.1.2 fullcalendar-scheduler@7.1.2 temporal-polyfill
```

```
import { Calendar } from 'fullcalendar'
import resourceTimelinePlugin from 'fullcalendar-scheduler/resource-timeline'
import classicThemePlugin from 'fullcalendar/themes/classic'
import jaLocale from 'fullcalendar/locales/ja'

const calendar = new Calendar(document.getElementById('calendar'), {
  schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives', // 評価用
  plugins: [classicThemePlugin, resourceTimelinePlugin],
  locale: jaLocale,
  timeZone: 'Asia/Tokyo',
  initialView: 'resourceTimelineDay',
  initialDate: '2026-10-05',
  resources: [
    { id: 'a', title: '会議室A' },
    { id: 'b', title: '会議室B' },
  ],
  events: [
    { title: '定例', start: '2026-10-05T10:00:00+09:00', end: '2026-10-05T11:00:00+09:00', resourceId: 'b' },
  ],
})
calendar.render()
```

このコードを7.1.2とjsdomで描画すると、会議室Aと会議室Bの行が並び、会議室Bの行に予定が表示されました。`schedulerLicenseKey` を消すと、カレンダーの下に「Your license key is invalid.」という表示が出ます。CSSは標準機能と同じ3枚で足ります。

## v7のインストール手順：npmとCDN

### npmで入れる手順（Vite・webpackなどのビルド環境）

本体と `temporal-polyfill` を一緒に入れます。`temporal-polyfill` はv7で全パッケージのpeerDependency（7.1.2では `^1.0.1`）になりました。FullCalendarは内部で使うだけでグローバルには登録しないため、アプリ全体でTemporal APIを使いたい場合は `import 'temporal-polyfill/global'` を自分で書きます。なお、Deno向けのレジストリであるJSRには、2026年10月14日時点で `@fullcalendar` のスコープがありません。配布先はnpmだけです。

```
npm install fullcalendar@7.1.2 temporal-polyfill
```

テーマもプラグインとして読み込み、CSSは `skeleton.css`（必須）、テーマの `theme.css`、配色のパレットCSSの3枚を読み込みます。v6と同じ見た目にしたい場合は `classic` テーマを選びます。

```
import { Calendar } from 'fullcalendar'
import dayGridPlugin from 'fullcalendar/daygrid'
import classicThemePlugin from 'fullcalendar/themes/classic'

import 'fullcalendar/skeleton.css'
import 'fullcalendar/themes/classic/theme.css'
import 'fullcalendar/themes/classic/palette.css'

const calendar = new Calendar(document.getElementById('calendar'), {
  plugins: [classicThemePlugin, dayGridPlugin],
  initialView: 'dayGridMonth',
  events: [{ title: '定例会議', start: '2026-10-05T10:00:00' }],
})
calendar.render()
```

v7のパッケージはESMだけで配布され、CommonJS版はなくなりました。公式の移行ガイドはNode.js 22.12以降と23以降なら `require('fullcalendar')` がそのまま動くとしており、Node.js 20系でも20.19.0以降は `require()` で同期ESMを読み込めます。ただし、トップレベルawaitを含むモジュールやJest独自の読み込み処理には別の制約があるため、テスト環境のESM対応を確認してください。ESMとCommonJSの違いは[Native ESMとCommonJSの違いを整理した記事](/tech/details/12462/)で解説しています。

### CDNのscriptタグで入れる手順

ビルド環境を使わない場合は、jsDelivrから読み込みます。v7ではファイル名が変わり、v6の `index.global.min.js` は `all/global.js` に、ロケールは `locales/ja/global.js` の形になりました。`all/global.js` には interaction・daygrid・timegrid・list・multimonth の各プラグインが入っています。以下のURLは7.1.2ですべて取得できることを確認済みです。

```
<script src="https://cdn.jsdelivr.net/npm/fullcalendar@7.1.2/all/global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/fullcalendar@7.1.2/themes/classic/global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/fullcalendar@7.1.2/locales/ja/global.js"></script>
<link href="https://cdn.jsdelivr.net/npm/fullcalendar@7.1.2/skeleton.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/fullcalendar@7.1.2/themes/classic/theme.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/fullcalendar@7.1.2/themes/classic/palette.css" rel="stylesheet">
<script>
  document.addEventListener('DOMContentLoaded', function () {
    var calendar = new FullCalendar.Calendar(document.getElementById('calendar'), {
      initialView: 'dayGridMonth',
      locale: 'ja',
    })
    calendar.render()
  })
</script>
<div id="calendar"></div>
```

URLのバージョンは `@7.1.2` のように固定してください。`@7` や無指定にすると、10月のように1週間で2回リリースが出たときに、気づかないまま表示が変わります。

## v6の記事のコードがv7で動かない原因

v6では本体が `@fullcalendar/core`、月表示が `@fullcalendar/daygrid` という別パッケージでした。v7ではこれらが `fullcalendar` のサブパスに統合されました。ところが `@fullcalendar/daygrid` などの旧プラグインはnpmに残っており、10月14日時点でもlatestは6.1.21を指したままです。`@fullcalendar/core` は7.1.2が出ていますが、v7では型定義用のパッケージになり、直接importすると「@fullcalendar/core should not be imported directly」と表示されて `Calendar` は取り出せません。そのため、v6の記事どおりに入れると、エラーにならずにv6とv7が混ざることがあります。

2026年9月27日に空のプロジェクトで試した結果は次のとおりです（npmのタグの状態は10月14日時点でも同じです）。

| 実行したコマンド・操作                                       | 結果                             |
| ------------------------------------------------- | ------------------------------ |
| `npm i @fullcalendar/react @fullcalendar/daygrid` | daygridは6.1.21、coreは2版が混在。警告なし |
| core 7系の導入後にdaygrid 6.1.21を追加                     | `ERESOLVE` で停止                 |
| v7本体にv6のdaygridプラグインを渡して描画                        | 描画時にTypeErrorで停止               |

2つ目はdaygridが `@fullcalendar/core@"~6.1.21"` を要求するため、3つ目のエラーメッセージは `TypeError: Class constructor DayTableView cannot be invoked without 'new'` でした。最初のケースはインストールが通るぶん、原因に気づきにくいパターンです。v7に移るときは、package.jsonから `@fullcalendar/core`・`@fullcalendar/daygrid`・`@fullcalendar/timegrid`・`@fullcalendar/list`・`@fullcalendar/interaction` を消し、import文を `fullcalendar/daygrid`（Reactなら `@fullcalendar/react/daygrid`）に書き換えます。Premiumの `@fullcalendar/resource-timeline` なども同様に、Vanilla JSでは `fullcalendar-scheduler/resource-timeline`、Reactでは `@fullcalendar/react-scheduler` に移っています。

パッケージ以外で書き換えが必要になる主な項目は次のとおりです。どれも旧名のままではエラーにならず、効かないだけなので見落としやすい箇所です。

- CSS：v6は自動で注入されていたが、v7では `skeleton.css` とテーマのCSSを明示的に読み込む
- イベントの色：`backgroundColor`・`borderColor` は `color` に、`textColor` は `contrastColor` に、`classNames`（配列）は `className`（空白区切りの文字列）に改名。カレンダー全体の `eventBackgroundColor` も `eventColor` に変わった
- クラスを付ける設定：`dayCellClassNames` などの `〜ClassNames` は `dayCellClass` のような `〜Class` に改名。7.1.2で旧名を渡すと、コンソールに「FullCalendar: Unknown option \`dayCellClassNames\`.」と出るだけでクラスは付かない
- タイムゾーン：`@fullcalendar/luxon3` と `@fullcalendar/moment-timezone` は廃止。名前付きタイムゾーンは本体だけで扱える
- Vue 2：`@fullcalendar/vue`（Vue 2用）はv7で提供終了。Vue 2のまま使うならv6に留まる

## 基本の使い方：ビュー切り替えとイベント表示

実務でよく使う設定をまとめると、次のようになります。月・週・リストの切り替えボタン、営業時間の網掛け、1日に入りきらない予定の「他 N 件」表示を入れた例です。先ほどのCSS3枚と、idがcalendarの描画先要素を用意した状態で実行します。

```
import { Calendar } from 'fullcalendar'
import dayGridPlugin from 'fullcalendar/daygrid'
import timeGridPlugin from 'fullcalendar/timegrid'
import listPlugin from 'fullcalendar/list'
import interactionPlugin from 'fullcalendar/interaction'
import classicThemePlugin from 'fullcalendar/themes/classic'
import jaLocale from 'fullcalendar/locales/ja'

const calendar = new Calendar(document.getElementById('calendar'), {
  plugins: [classicThemePlugin, dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin],
  locale: jaLocale,
  timeZone: 'Asia/Tokyo',
  initialView: 'dayGridMonth',
  initialDate: '2026-10-01',
  headerToolbar: {
    left: 'prev,next today',
    center: 'title',
    right: 'dayGridMonth,timeGridWeek,listWeek',
  },
  businessHours: { daysOfWeek: [1, 2, 3, 4, 5], startTime: '09:00', endTime: '18:00' },
  dayMaxEvents: true,
  eventColor: '#2563eb',
  events: '/api/events',
})
calendar.render()
```

`initialView` に指定できるのは、読み込んだプラグインが提供するビューだけです。`dayGridMonth` はdaygrid、`timeGridWeek` はtimegrid、`listWeek` はlistが必要で、年間表示の `multiMonthYear` を使うなら `fullcalendar/multimonth` を追加します。`headerToolbar` の `right` に並べたビュー名が、そのまま切り替えボタンになります。

## 日本語化とタイムゾーンの設定

### 日本語化（locale: ja）

npmで入れた場合は `fullcalendar/locales/ja` をimportして `locale` に渡し、CDNの場合は `locales/ja/global.js` を読み込んでから `locale: 'ja'` を指定します。7.1.2同梱の日本語ロケールでは、ボタンが「前」「次」「今日」「月」「週」「日」「予定リスト」、終日欄が「終日」、あふれた予定が「他 N 件」、予定が無いリストが「表示する予定はありません」になります。

日本語ロケールには週の開始曜日の指定が入っていないため、既定の日曜始まりになります。月曜始まりにしたい場合は `firstDay: 1` を追加してください。jsdomで描画すると、曜日の見出しが月曜から並びました。

### 名前付きタイムゾーン（timeZone）

`timeZone` の既定値は `'local'`（閲覧者のブラウザの時刻）です。v7では `'Asia/Tokyo'` のようなIANAのタイムゾーン名を、追加プラグインなしで指定できます。v6では名前付きタイムゾーンにLuxonかmoment-timezoneの連携プラグインが必要でしたが、v7ではpeerDependencyの `temporal-polyfill` を内部で使って解決します。

注意点は、コールバックやAPIが返す日付がTemporalではなく従来のJavaScriptの `Date` のままであることです。公式ドキュメントも、返ってくる `Date` が実質的に扱えるのはローカルとUTCだけだとしています。`Asia/Tokyo` を指定していても `getHours()` は閲覧者のPCのタイムゾーンで値を返すため、サーバーに送る値は `startStr`（オフセット付きのISO 8601文字列）を使うのが安全です。

### 日本の祝日を表示する方法

FullCalendarには祝日のデータが入っていません。内閣府が公開している [国民の祝日CSV](https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv)（1955年から翌年分までを収録・Shift\_JIS）をサーバー側で読み込み、背景イベントとして返すのが手軽です。

```
{ "title": "スポーツの日", "start": "2026-10-12", "allDay": true, "display": "background", "color": "#fde2e2" }
```

`display: 'background'` を付けると、予定の下に色の帯として描画されます。翌年分は毎年2月の掲載後に取得し、収録年の末尾も確認してください。年初に取得するだけでは、翌年分の追加を取り逃がす可能性があります。

## 見た目のカスタマイズ：テーマ・色・土日の色分け

v7のカスタマイズは、テーマとパレットを選ぶ、CSS変数で色を差し替える、`〜Class` 系の設定で自分のクラスを付ける、の順で考えます。最初に知っておきたいのは、v7が描画する要素のクラス名が `fc-classic-uqo` のような短い記号になっている点です。7.1.2をjsdomで描画して全要素のクラスを調べたところ、v6の `fc-day-sat`・`fc-daygrid-day`・`fc-event` のような意味のあるクラスは1つも出力されず、残っていた手がかりは日セルの `data-date` 属性だけでした。v6向けの記事にある「`.fc-day-sat` に背景色を付ける」CSSは、v7では何にも当たりません。

### テーマとパレットの選び方

テーマは5種類で、それぞれに配色のパレットがあります。[公式のテーマ一覧](https://fullcalendar.io/docs/stock-themes)によると、内訳は次のとおりです。全テーマがダークモードに対応し、[themes.fullcalendar.io](https://themes.fullcalendar.io/) で見比べられます。

| テーマ     | デザインの元            | パレット（太字が既定）                      |
| ------- | ----------------- | -------------------------------- |
| Monarch | Material Design 3 | blue・green・**purple**・red・yellow |
| Forma   | Fluent UI         | **blue**・green・purple・red        |
| Breezy  | Tailwind Plus     | amber・emerald・**indigo**・rose    |
| Pulse   | Apple風の簡素なデザイン    | blue・green・purple・**red**        |
| Classic | v6までの見た目          | 1種類のみ                            |

パレットCSSのパスはテーマによって違います。Classicだけが `themes/classic/palette.css` の1枚で、ほかの4テーマは `themes/monarch/palettes/blue.css` のように色名のファイルを選びます。既存のv6画面に近づけるならClassic、Material Design 3に合わせるならMonarch、Fluent UIに合わせるならFormaが候補です。配色の変更は、ほかの標準テーマでもパレットCSSで行えます。shadcn・MUI・Bootstrap 5を使っている画面では、それぞれのライブラリのテーマから見た目を取る専用の連携が用意されています。

### CSS変数によるパレット色の上書き

パレットの一部の色だけを変えたいときは、パレットCSSの後に自分のCSSを読み込み、`:root` でCSS変数を上書きします。パレットはそのまま使うので、本体の更新で入る修正も受け取れます。Classicの `palette.css` には、主色の `--fc-classic-primary`（既定 `#3788d8`）、今日のセルの `--fc-classic-today`、現在時刻の線の `--fc-classic-now`、枠線の `--fc-classic-border` など27個の変数が定義されています。

```
/* my-calendar.css（palette.cssの後に読み込む） */
:root {
  --fc-classic-primary: #0f766e;
  --fc-classic-today: #fef3c7;
}
@media not print {
  [data-color-scheme=dark] {
    --fc-classic-today: #78350f66;
  }
}
```

ダークモードは、親要素に `data-color-scheme="dark"` を付けるだけで切り替わります。ダークモードをクラス名や独自のメディアクエリで切り替えている場合は、この上書きが効かないため、公式の案内どおりパレットCSSを自分のプロジェクトへ複製して書き換えてください。予定ごとの色は `eventColor` やイベントの `color` で指定し、描画時に `--fc-event-color` として要素へ渡されます。

### 土日・祝日セルの色分け（dayCellClass）

土日の色分けは、`dayCellClass`（日セル）と `dayHeaderClass`（曜日の見出し）に関数を渡し、自分のクラスを返して行います。関数が受け取る情報には、7.1.2の型定義で曜日の番号 `dow`（0が日曜、6が土曜）が含まれています。

```
const weekendClass = (info) => (info.dow === 0 ? 'is-sun' : info.dow === 6 ? 'is-sat' : '')

const calendar = new Calendar(calendarEl, {
  // plugins・locale などは前の例と同じ
  dayCellClass: weekendClass,
  dayHeaderClass: weekendClass,
})
```

```
/* 自分で付けたクラスなら、v7でもCSSで指定できる */
.is-sat { background: #eff6ff; color: #1d4ed8; }
.is-sun { background: #fef2f2; color: #b91c1c; }
```

2026年10月の月表示（月曜始まり）で描画すると、土曜と日曜の列にそれぞれクラスが付きました。同じ設定を `dayCellClassNames` という旧名で渡したときは、クラスは1つも付かず、警告だけが出ました。祝日も同じ関数の中で、サーバーから取った祝日の日付と照らし合わせてクラスを返せば色分けできます。週表示の時間帯の列には `dayCellClass` ではなく `dayLaneClass` を使います。

### 時間軸の範囲・間隔と高さの調整

週・日表示の時間軸は、`slotMinTime`（既定 `00:00:00`）、`slotMaxTime`（既定 `24:00:00`・その時刻を含まない）、`slotDuration`（既定 `00:30:00`）で決まります。業務時間だけを見せる設定は次のとおりです。

```
slotMinTime: '08:00:00',
slotMaxTime: '20:00:00',
slotDuration: '00:30:00',
nowIndicator: true, // 現在時刻の線を出す（既定はfalse）
height: 'auto',     // スクロールせず全体を表示する
```

この設定で週表示を描画すると、時刻の目盛りは「8時」から「19時」まで並びました。`slotMaxTime` は終端を含まないため、20時の目盛りは出ません。`height` は未指定なら `aspectRatio` から計算され、`'auto'` を指定するとスクロールなしで全体が表示されます。

予定の時刻表記は `eventTimeFormat` で変えられます。`{ hour: '2-digit', minute: '2-digit', hour12: false }` を指定すると、月表示では「09:00」になりました。ただし、同じ指定のまま7.1.2の週表示をjsdomで描画した結果は「9時00分～10時30分」のままでした。公式ドキュメントは、既定値はビューごとに違うものの、1つの設定で全ビューに効くと説明しています。今回の結果はこの説明と食い違い、`views` で週表示（timeGrid）だけに同じ書式を指定しても変わりませんでした。原因は確定できていないため、週表示の書式は実際のブラウザで確かめてください。

### ツールチップとリンク遷移（eventDidMount・url）

マウスを乗せたときに補足を出すには、予定の要素がDOMに入った直後に呼ばれる `eventDidMount` を使います。公式デモはここでTooltip.jsを適用していますが、ブラウザ標準の `title` 属性でも足ります。

```
eventDidMount(info) {
  info.el.setAttribute('title', info.event.extendedProps.memo ?? '')
},
events: [
  { title: '定例会議', start: '2026-10-05T09:00:00+09:00', extendedProps: { memo: '第3会議室' } },
  { title: '仕様書', start: '2026-10-07', url: 'https://example.com/spec' },
],
```

`url` を持つ予定は `a` 要素として描画され、jsdomでも `href` にURLが入っていました。クリックすると同じタブで遷移します。別タブで開きたい場合は、`eventClick` の中で `info.jsEvent.preventDefault()` を呼んでから `window.open(info.event.url)` を実行します。

## クリック・ドラッグによるイベントの追加・編集・削除

日付のクリック（`dateClick`）、範囲選択（`select`）、予定のドラッグ移動（`eventDrop`）、長さの変更（`eventResize`）には `fullcalendar/interaction` が必要です。予定のクリック（`eventClick`）だけならinteractionなしで動きます。`dateClick` やドラッグが反応しない場合は、interactionプラグインの読み込みと、`editable: true`・`selectable: true` の指定を確認してください。CDNの `all/global.js` にはinteractionが含まれています。

```
const calendar = new Calendar(calendarEl, {
  // plugins などは前の例と同じ
  selectable: true, // 範囲選択を有効にする
  editable: true,   // ドラッグ移動と長さ変更を有効にする

  select(info) {
    const title = prompt('予定名')
    if (title) {
      calendar.addEvent({ title, start: info.startStr, end: info.endStr, allDay: info.allDay })
    }
    calendar.unselect()
  },

  eventClick(info) {
    if (confirm(`「${info.event.title}」を削除しますか？`)) info.event.remove()
  },

  async eventDrop(info) {
    if (!info.event.id) { // selectで追加しただけの未保存の予定はidがない
      info.revert()
      return
    }
    const res = await fetch(`/api/events/${info.event.id}`, {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ start: info.event.startStr, end: info.event.endStr, allDay: info.event.allDay }),
    }).catch(() => null)
    if (!res || !res.ok) info.revert() // 保存に失敗したら元の位置へ戻す
  },
})
```

`addEvent` や `remove` は画面上の予定を変えるだけで、サーバーには何も送りません。7.1.2でも、読み込み済みの3件に `addEvent` で1件足すと4件、その予定の `remove()` で3件に戻るだけでした。`eventDrop` の例のように、保存APIの呼び出しと失敗時の `info.revert()` を組にしておくと、画面とデータベースの食い違いを防げます。`eventResize` にも同じ `revert()` があります。

## データベース連携：JSONフィードのstart・endと応答形式

`events` にURLを渡すと、FullCalendarは表示中の期間を `start` と `end` のGETパラメータに入れて取りに来ます。前後の月へ移動したときやビューを切り替えたときに、必要な範囲だけ再取得する仕組みです。7.1.2で `timeZone: 'Asia/Tokyo'` を指定し、2026年10月の月表示を開いたとき、サーバーに届いたクエリは次のとおりでした（URLデコード済み）。

```
/api/events?start=2026-09-27T00:00:00+09:00&end=2026-11-08T00:00:00+09:00&timeZone=Asia/Tokyo
```

この例は日曜始まり・6週表示のため、取得範囲は9月27日から11月8日までです。月曜始まりに変更した場合は、この範囲も変わります。`end` はその時刻を含まない排他的な終端です。サーバー側では、この範囲と少しでも重なる予定を返します。下のサーバーに12月の予定と9月25日から29日までの連泊予定をテストデータとして足して確認したところ、12月の予定は返らず、連泊予定は表示されました。

読み取り用のJSONフィードを、依存パッケージなしのNode.jsで書くと次のようになります。HTMLの配信と前章のPATCHによる保存は実装していないため、画面側の開発サーバーでこのAPIへのプロキシを設定し、保存APIは別に用意してください。

```
// server.mjs（Node.js 22以降・依存パッケージなし）
import http from 'node:http'

const events = [
  { id: '1', title: '定例会議', start: '2026-10-05T10:00:00+09:00', end: '2026-10-05T11:00:00+09:00' },
  { id: '2', title: '出張', start: '2026-10-14', end: '2026-10-17', allDay: true },
]

// 日付だけの値（終日予定）は日本時間の0時として扱う
const toMs = (v) => Date.parse(v.length === 10 ? `${v}T00:00:00+09:00` : v)

http.createServer((req, res) => {
  const url = new URL(req.url, 'http://localhost')
  if (url.pathname !== '/api/events') { res.writeHead(404).end(); return }
  const from = Date.parse(url.searchParams.get('start'))
  const to = Date.parse(url.searchParams.get('end')) // 排他的な終端
  const hits = events.filter((e) => {
    const start = toMs(e.start)
    // end省略時はFullCalendarの既定の長さ（終日1日・時刻付き1時間）を補う
    const allDay = e.allDay ?? e.start.length === 10
    const end = e.end ? toMs(e.end) : start + (allDay ? 86400000 : 3600000)
    return start < to && end > from
  })
  res.writeHead(200, { 'Content-Type': 'application/json' })
  res.end(JSON.stringify(hits))
}).listen(3000)
```

SQLで書くなら条件は `WHERE start_at < :end AND end_at > :start` です。`start_at >= :start` だけで絞ると、前月から続く連泊の出張のように、範囲の開始より前に始まる予定が消えます。パラメータ名は `startParam`・`endParam` で変えられるので、既存APIの引数名に合わせることもできます。

この例では、表示用の `title`・`start` に加え、保存APIで予定を識別するための `id` を返します。`end` は終日予定なら翌日の日付（10月14日から16日までの3日間なら `"end": "2026-10-17"`）を入れます。APIを別ドメインに置く場合はCORSの設定も必要で、手順は[CORSの仕組みとサーバー設定例の記事](/tech/details/13763/)にまとめています。

## React・Vue・Angularで使う場合のパッケージ

公式のコネクタは、v7でそれぞれのフレームワーク用パッケージの中にプラグインとテーマを抱える形になりました。Vanilla JS用の `fullcalendar` を別に入れる必要があるのはAngularだけです。対応バージョンは7.1.2の各パッケージのpeerDependenciesで確認しました。

| フレームワーク | 標準パッケージ                                  | 対応バージョン       | Premium用                          |
| ------- | ---------------------------------------- | ------------- | --------------------------------- |
| React   | `@fullcalendar/react`                    | React 17〜19   | `@fullcalendar/react-scheduler`   |
| Vue     | `@fullcalendar/vue3`                     | Vue 3.0.11以降  | `@fullcalendar/vue3-scheduler`    |
| Angular | `@fullcalendar/angular` ＋ `fullcalendar` | Angular 16〜22 | `@fullcalendar/angular-scheduler` |
| MUI     | `@fullcalendar/mui`                      | MUI v7・v9     | peerにreact-schedulerを含む           |

Reactのコネクタは、v6までは内部でPreactを動かすラッパーでしたが、v7ではReactで実装し直され、SSRとStrictModeでも動くようになりました（Preact用には `@fullcalendar/preact` が新設）。Preactとの違いは[Preactの仕組みとReactとの違いの記事](/tech/details/16011/)で扱っています。Reactでの最小構成は次のとおりです。

```
import FullCalendar from '@fullcalendar/react'
import dayGridPlugin from '@fullcalendar/react/daygrid'
import classicThemePlugin from '@fullcalendar/react/themes/classic'
import jaLocale from '@fullcalendar/react/locales/ja'
import '@fullcalendar/react/skeleton.css'
import '@fullcalendar/react/themes/classic/theme.css'
import '@fullcalendar/react/themes/classic/palette.css'

export default function Schedule() {
  return (
    <FullCalendar
      plugins={[classicThemePlugin, dayGridPlugin]}
      initialView="dayGridMonth"
      locale={jaLocale}
      events="/api/events"
    />
  )
}
```

MUIで画面を組んでいる場合は、`@fullcalendar/mui` を使うとMUIのテーマから色と部品を取ります。7.1.1でMUI v9に対応しており、MUI側の構成は[Material UIのv9系の導入とテーマ設定の記事](/tech/details/17551/)が参考になります。Angularは `angular.json` の `styles` に3枚のCSSを登録し、テンプレートで `<full-calendar [options]="calendarOptions">` を使います。Angular側のバージョン事情は[Angular 22.1の変更点の記事](/tech/details/15980/)にまとめています。

## FullCalendarを選ばないほうがよい場面

予定を並べて操作するUIならFullCalendarは第一候補ですが、次の条件に当てはまるなら別の手段を検討してください。

- 日付を1つ選ばせるだけの入力欄：カレンダー表示は過剰です。`<input type="date">` か日付ピッカーのライブラリで足ります
- 非公開の業務システムでタイムラインやリソース別の表示が必須なのに予算化できない：Premiumの商用ライセンスが開発者の人数分かかります。標準機能の週表示をリソースごとに並べる設計に変えるか、他のライブラリと比べてください
- Vue 2のまま改修を続けるシステム：v7のVue 2対応はありません。v6.1.21に固定し、Vue 3への移行と同時にv7へ上げる計画にします
- v6向けのCSSを大量に書き込んだ画面：v7ではクラス名で要素を指定できなくなるため、CSSの書き直しが前提になります。見た目を作り込んだv6の画面ほど移行の工数が膨らみます

既存のv6を動かしているシステムを、機能追加の予定もないのにv7へ上げる必要はありません。CSS・色の設定名・パッケージ名の書き換えが一度に発生するため、画面改修のタイミングに合わせるのが現実的です。会議室や設備の予約、空き枠の管理までを含めた仕組みをまとめて作る場合は、[予約管理システムの開発支援](/service/system/reservation/)のように、カレンダー画面とデータベース・予約ルールを一体で設計する選択肢もあります。ライブラリのライセンスの考え方全般は[OSSのライセンス種別と採用判断の記事](/tech/details/13437/)で整理しています。

## よくある質問

### FullCalendarは無料で商用利用できますか？

Premiumと印の付いていない標準機能はMITライセンスで、商用のシステムでも無料で使えます。タイムライン表示やリソース表示などのPremium機能を非公開の商用システムで使う場合は、480ドルからの商用ライセンスが必要です。

### FullCalendarの最新バージョンはいくつですか？

2026年10月14日時点の最新は7.1.2（2026年10月12日公開）です。npmで `fullcalendar` を入れるとv7が入ります。同日時点のv6系の最新は6.1.21（2026年6月18日公開）です。

### FullCalendarを日本語化するにはどうすればよいですか？

npmなら `import jaLocale from 'fullcalendar/locales/ja'` を `locale` に渡し、CDNなら `locales/ja/global.js` を読み込んで `locale: 'ja'` を指定します。月曜始まりにしたい場合は `firstDay: 1` を追加します。

### 土曜・日曜の色を変えるCSSが効かないのはなぜですか？

v7では描画される要素のクラス名が短い記号になり、v6の `.fc-day-sat` や `.fc-day-sun` が出力されないためです。`dayCellClass` と `dayHeaderClass` に関数を渡して、曜日に応じた自分のクラスを付け、そのクラスにCSSを書きます。v6の `dayCellClassNames` という名前ではクラスは付きません。

### v6の解説記事のコードをv7で使えますか？

そのままでは動きません。`@fullcalendar/core` を `fullcalendar` に、`@fullcalendar/daygrid` などを `fullcalendar/daygrid` のサブパスに置き換え、`skeleton.css` とテーマのCSSを読み込む必要があります。`@fullcalendar/daygrid` を入れるとv6.1.21が入り、v7本体と混ざってエラーになります。

## 関連記事

- [Preactとは？Reactとの違い・導入手順・compat移行と採用判断【2026年9月版】](/tech/details/16011/)
- [ESMとCommonJSの違い｜require(esm)で変わった相互運用と移行](/tech/details/12462/)
- [CORSとは？仕組み・プリフライト・サーバー設定例・エラー解決を実装目線で解説](/tech/details/13763/)
- [Material UIとは：v9系の導入からGrid・テーマ設定までコード付きで解説](/tech/details/17551/)
- [オープンソースソフトウェア（OSS）とは｜ライセンス種別と実装現場での採用判断・リスク管理](/tech/details/13437/)

---

出典: [FullCalendarとは？v7.1.2の導入・使い方・日本語化・カスタマイズとv6からの移行を解説](<https://www.issoh.co.jp/tech/details/4742/>)（株式会社一創）
