My Website

Using Svelte with Eleventy

Combine Eleventy's speed with Svelte 5's modern reactivity by precompiling Svelte components with Vite and rendering them via Eleventy's Render Plugin. Use is-land for client-side hydration. This setup isolates server-side HTML generation while keeping interactivity.

  1. Project Scaffolding

Create a workspace structure separating Eleventy templates and Svelte source files. Initialize your Node project and configure Vite to build your components:

bashmkdir eleventy-svelte5
cd eleventy-svelte5
npm init -y
npm install @11ty/eleventy svelte vite @sveltejs/vite-plugin-svelte @11ty/eleventy-plugin-is-land
  1. Configure Vite

Create a vite.config.js file in your root directory to compile Svelte components (including Svelte 5 runes) into vanilla JavaScript:

import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';

export default defineConfig({
  plugins: [svelte()],
  build: {
    rollupOptions: {
      input: 'src/components/main.js',
      output: {
        dir: '_site/assets',
        entryFileNames: 'bundle.js',
        format: 'iife'
      }
    }
  }  
});
  1. Eleventy & Hydration Setup

In your eleventy.config.js (or eleventy.config.mjs), register the component to handle client-side hydration and pass Svelte props safely:

import { EleventyRenderPlugin } from "@11ty/eleventy";
import isLandPlugin from "@11ty/eleventy-plugin-is-land";

export default function(eleventyConfig) {
  eleventyConfig.addPlugin(EleventyRenderPlugin);
  eleventyConfig.addPlugin(isLandPlugin);
  
  // Pass through compiled Vite assets
  eleventyConfig.addPassthroughCopy("_site/assets");
}
  1. Create Svelte 5 Components

Write your components in src/components/, utilizing Svelte 5 features like snippets and runes.

<!-- src/components/Counter.svelte -->
<script>
  let { initialValue = 0 } = $props();
  let count = $state(initialValue);
  
  function increment() {
    count += 1;
  }
</script>

<div class="counter">
  <p>Count: {count}</p>
  <button onclick={increment}>Increment</button>
</div>
  1. Consuming in Eleventy Pages

Use Eleventy's Universal Render filter in your Markdown or Nunjucks pages.

---
title: My Svelte 5 Page
layout: base.njk
---

<h1>Welcome to Eleventy + Svelte</h1>

&lt;!-- Statically render the component HTML using Eleventy Render Plugin --&gt;

&lbrace;% render "./src/components/Counter.svelte", { initialValue: 10 } %&rbrace;

<!-- Hydrate interactively client-side using <is-land> and Vite bundle -->
<is-land on:visible>
  <div id="svelte-root"></div>
  <script type="module">
    import { mount } from '/assets/bundle.js'; // Assumes you bundle properly
    import Counter from './src/components/Counter.svelte';
    mount(Counter, { target: document.getElementById('svelte-root'), props: { initialValue: 10 } });
  </script>
</is-land>

Use code with caution.Could you share whether you are building a primarily static site with light interactivity, or a highly dynamic app? I can tailor the Vite bundling or hydration strategy to fit your specific goal.

Vite configuration

For a static site with light interactivity, you do not need a massive SPA bundle. Instead, use an island-based approach: generate lightweight static HTML during the Eleventy build and only ship mini-JS script tags to hydrate interactive spots when they enter the viewport.

The cleanest workflow uses Eleventy's Custom File Extension Handler to parse Svelte files during the build, combined with an eleventy-plugin-vite bridge to automate compilation.

  1. Project Dependencies

Install the official Eleventy-Vite plugin alongside Svelte 5 and the Svelte-Vite plugin:bashnpm install @11ty/eleventy svelte vite @sveltejs/vite-plugin-svelte eleventy-plugin-vite @11ty/eleventy-plugin-is-land

  1. Configure Eleventy & Vite Together

This setup catches .svelte files, extracts their markup for zero-JS static HTML by default, and registers is-land for lazy client-side hydration.

Create or update eleventy.config.js

import { compile } from 'svelte/compiler';

import eleventyVitePlugin from 'eleventy-plugin-vite';
import isLandPlugin from '@11ty/eleventy-plugin-is-land';
import { svelte } from '@sveltejs/vite-plugin-svelte';

export default function(eleventyConfig) {
  eleventyConfig.addPlugin(isLandPlugin);

  // 1. Tell Eleventy how to render Svelte files as static HTML templates
  eleventyConfig.addExtension("svelte", {
    compileOptions: {
      cache: false,
    },
    compile: async function(inputContent) {
      return async (data) => {
        // Compile component on the server side
        const { js } = compile(inputContent, { generate: 'server' });
        
        // Convert compiled JS into a temporary module to run it
        const base64Module = "data:text/javascript;base64," + Buffer.from(js.code).toString('base64');
        const Component = (await import(base64Module)).default;
        
        // Svelte 5 server-side API renders the static HTML string
        const result = Component(data); 
        return result.html; 
      };
    }
  });

  // 2. Add Vite plugin to process client-side scripts seamlessly
  eleventyConfig.addPlugin(eleventyVitePlugin, {
    viteOptions: {
      plugins: [svelte()],
    }
  });
}
  1. Build Your Interactive Svelte Component

Keep your interactivity sandboxed inside your .svelte component using Svelte 5's $state and $props runes.

&lt;!-- _includes/components/LikeButton.svelte --&gt;
<script>
  let { initialLikes = 0 } = $props();
  let likes = $state(initialLikes);
</script>

<button class="like-btn" onclick={() => likes++}>
  ❤️ {likes} Likes
</button>

<style>
  .like-btn { padding: 0.5rem 1rem; border-radius: 4px; cursor: pointer; }
</style>
  1. Inject Islands Into Markdown Pages

Instead of global bundles, write a microscopic hydration script directly inside your layout or page. Pass server-side Eleventy data straight into your Svelte props dynamically.

---
title: My Blog Post
layout: base.njk
likesCount: 12
---

<h1>Using Svelte with Eleventy</h1>
<p>This is a fast, static page generated by Eleventy.</p>

<!-- 1. Pure Server-Side HTML Rendering (Zero JS) -->
<div id="like-button-island">
  &lbrace;% renderFile "./_includes/components/LikeButton.svelte", { initialLikes: likesCount } %&rbrace;
</div>

<!-- 2. Client-Side Lazy Hydration via <is-land> -->
<is-land on:visible>
  <script type="module">
    import { hydrate } from 'svelte';
    import LikeButton from './_includes/components/LikeButton.svelte';

    // Svelte 5 hydration hooks into the server-rendered HTML nodes
    hydrate(LikeButton, {
      target: document.getElementById('like-button-island'),
      props: { initialLikes:  }
    });
  </script>
</is-land>
  1. Start Your Project

Eleventy-plugin-vite intercepts your local dev environment and automatically creates lean entry points for any inline module scripts you use.

# Run local development server
npx @11ty/eleventy --serve

# Build your production-optimized static site
npx @11ty/eleventy