Skip to content
Guide

FullCalendar in SvelteKit

FullCalendar depends on the DOM, so treat it like a client-only widget. Import the core and plugins on mount, render once, and destroy cleanly when the component unmounts.

Best practices

  • Gate Calendar creation behind onMount to avoid SSR mismatches.
  • Keep event data separate from calendar setup so updates stay predictable.
  • Use height: "auto" for responsive layouts inside SvelteKit shells.
  • Destroy the instance on unmount to clear listeners and observers.
  • Keep plugin lists explicit so bundles stay trimmed.

SvelteKit-friendly setup

<script lang="ts">
	import { onMount } from "svelte";
	import type { Calendar } from "@fullcalendar/core";

	let calendarEl: HTMLDivElement | null = null;
	let calendar: Calendar | null = null;

	onMount(() => {
		let active = true;

		const init = async () => {
			const [{ Calendar }, dayGridPlugin] = await Promise.all([
				import("@fullcalendar/core"),
				import("@fullcalendar/daygrid")
			]);

			if (!active || !calendarEl) return;

			calendar = new Calendar(calendarEl, {
				plugins: [dayGridPlugin.default],
				initialView: "dayGridMonth",
				height: "auto"
			});
			calendar.render();
		};

		void init();

		return () => {
			active = false;
			calendar?.destroy();
		};
	});
</script>

<svelte:head>
	<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fullcalendar/core@6.1.20/index.css" />
	<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fullcalendar/daygrid@6.1.20/index.css" />
</svelte:head>

Checklist

  • onMount gates FullCalendar access.
  • Plugins are explicit and minimal.
  • Cleanup calls destroy() on unmount.
Built as a personal SvelteKit 5 lab with Supabase auth. Guides, patterns, and a playground you can actually ship.
Command Palette
Search for a command to run