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
onMountto 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
onMountgates FullCalendar access.- Plugins are explicit and minimal.
- Cleanup calls
destroy()on unmount.