Integrate Eleventy with Storyblok
Use Storyblok to manage the content of your Eleventy website.
Create a new Eleventy project in a few simple steps by following the Get Started page from its official documentation.
If you already have a Storyblok account, go to app.storyblok.com or log in with GitHub to continue.
Create a new blank space (opens in a new window) to follow the tutorial from scratch, or start from the core blueprint (opens in a new window).
Installation
Section titled “Installation”In your terminal, cd into your Eleventy project and install the @storyblok/js and dotenv packages.
npm install @storyblok/js dotenv --save-devIn the root of your project, create a .env file with the access token from your space.
STORYBLOK_DELIVERY_API_TOKEN="fqc3tdIuC8djNwEYl5cE5Att"Every Eleventy project requires a config file at root. Create one with the following content.
export default function eleventy() {
return { dir: { input: 'src', }, };}Create a storyblok.js file under the src/_utils directory and add this code:
import { apiPlugin, storyblokInit } from '@storyblok/js';import 'dotenv/config';
const { storyblokApi } = storyblokInit({ accessToken: process.env.STORYBLOK_DELIVERY_API_TOKEN, apiOptions: { region: 'eu', // Choose the correct region from your Space. }, use: [apiPlugin],});
export default storyblokApi;The Storyblok module will make features like fetching, components registration and bridge available for your project.
Fetch a single story
Section titled “Fetch a single story”Create a home.js data file and use the client instance to fetch a story’s data.
import storyblok from '../_utils/storyblok.js';
export default async function home() { const response = await storyblok.get("cdn/stories/home", { version: "draft", // or "published" });
const { story } = response.data; const name = story.content.name; const body = story.content.body;
return { name, body };}In a data file, we fetch a single story by its slug and return the content properties we want to use in our templates.
Create a layout file as required by Eleventy to render a page.
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>{{ title }}</title></head><body> {{ content }}</body></html>Use the name of the data file on a content file as a namespace to access properties in the content area, or in the front matter through eleventyComputed to pass them to the layout.
---layout: 'layouts/base.liquid'eleventyComputed: title: '{{ home.name }}'permalink: '/'---
<main> {{ home.body }}</main>Eleventy can handle text based fields, and even Markdown with no configuration.
However, we need to deal with custom components within our space for a valid output.
Create and register blocks
Section titled “Create and register blocks”Stories might contain a body or similar field which consists of an array with several blocks of custom types (e.g. Feature, Teaser, Grid) in it.
Create a function for each component that returns the resulting HTML for each.
function Feature(blok) { return ( `<div class="feature"> <span>${blok.name}</span> </div>` );}
export default Feature;function Teaser(blok) { return ( `<div class="teaser"> <h2>${blok.headline}</h2> </div>` );}
export default Teaser;import Feature from './feature.js';import Teaser from './teaser.js';
function Grid(blok) { return ( `<div class="grid"> ${blok.columns.map((nestedBlok) => { switch (nestedBlok.component) { case 'feature': return Feature(nestedBlok); case 'teaser': return Teaser(nestedBlok); default: throw new Error(`Grid could not resolve ${nestedBlok.component}.`); } }).join('')} </div>` );}
export default Grid;Iterate over the body array and resolve each component.
import storyblok from '../_utils/storyblok.js';import Feature from '../_components/feature.js'import Teaser from '../_components/teaser.js'import Grid from '../_components/grid.js'
export default async function home() { const response = await storyblok.get("cdn/stories/home", { version: "draft", // or "published" });
const { story } = response.data; const name = story.content.name; const body = story.content.body .map(blok => { switch (blok.component) { case 'feature': return Feature(blok); case 'teaser': return Teaser(blok); case 'grid': return Grid(blok); default: throw new Error(`Could not resolve ${blok.component} block.`); } }) .join('');
return { name, body };}Similar to our Grid component, use the body to iterate over all blocks and render the corresponding one.
Run the server and visit the site in your browser.
npx @11ty/eleventy --serveRelated resources
Section titled “Related resources”Get in touch with the Storyblok community