Going Beyond Static With Eleventy
Stephanie Eckles @5t3ph
11ty.Rocks • ModernCSS.dev • StyleStage.dev
Do you enjoy being a maker of the web?













Key Features

Key Features
100% Static Output
⚡️
zero boilerplate client-side JavaScript

Key Features
Developer-Mode Conveniences
⚡️
includes Browsersync for hot-reload

Key Features
Minimal Opinions, Highly Configurable
⚡️
only an `index` required, config as needed
.eleventy.js

Key Features
Minimal Opinions, Highly Configurable
.eleventy.js
customize input/output dir, add plugins, filters, and shortcodes

Key Features
10 Templating Languages
⚡️
templating not required, add in as needed

Key Features
10 Templating Languages


Key Features
Mix Templating Languages
- Mix in the same file (ex. Nunjucks and Markdown)
- Mix between layouts (Markdown file uses Nunjucks template)

Key Features
Layouts
special templates that can be used to wrap other content
---
title: Hello World
---
Welcome to my amazing 11ty website!
<!DOCTYPE html>
<html lang="en">
<head>
<title>{{ title }}</title>
</head>
<body>
{{ content | safe }}
</body>
</html>
index.md
base.njk
---
title: Hello World
---
Welcome to my amazing 11ty website!
<!DOCTYPE html>
<html lang="en">
<head>
<title>{{ title }}</title>
</head>
<body>
{{ content | safe }}
</body>
</html>
➡️
➡️
index.md
base.njk
---
title: News Post
layout: page.njk
---
A news posting.
<!DOCTYPE html>
<html lang="en">
<head>
<title>{{ title }}</title>
</head>
<body>
{{ content | safe }}
</body>
</html>
➡️
➡️
base.njk
Layout Chaining
---
layout: base.njk
---
<header>
<h1>{{ title }}</h1>
</header>
<article>
{{ content | safe }}
</article>
page.njk
---
title: Article
layout: page.njk
---
A blog article.
➡️

Key Features
Extended Templating
- include other files as partials
- shortcodes for reusable content
- filters to manipulate content
11ty.dev/docs/config/

Key Features
Template Engine Overrides
override per file or in .eleventy.js

Key Features
Template Engine Overrides
---
templateEngineOverride: njk, md
---
## Featured Person
{% for name in people | randomPerson %}
- {{ name }}
{% endfor %}

Key Features
Custom
Data
included in `_data/`, created as JSON or JS modules

Key Features
Custom
Data
module.exports = [
"Mary",
"Claire",
"Steph",
"Andy"
];
_data/people.js
## Featured Person
{% for name in people %}
- {{ name }}
{% endfor %}
➡️

Key Features
External Data
fetch and format for your needs

Key Features
External Data
const axios = require("axios");
module.exports = async () => {
const result = await axios.get("https://aws.random.cat/meow");
return result.data.file;
// Ex: https:\/\/purr.objects-us-east-1.dream.io\/i\/image1-4.jpg
};
fetched at build, not client-side

Key Features
Content Management
create `collections` for related content types using `tags`

Key Features
Collections
From Tags
can be added in
front matter
---
tags: post
# or
tags: ['post', 'webdev']
---

Key Features
Collections
From Tags
can be defined in directory data files
{
"layout": "post.njk",
"tags": "posts"
}
posts/posts.json

Key Features
Collections
From Tags
{
"layout": "post.njk",
"tags": "posts"
}
posts/posts.json
{% for post in collections.post -%}
- [{{ post.data.title }}]({{ post.url }})
{% endfor %}
[any template]

Key Features
Feature Integration
use anything in the Node/JS ecosystem at build time
<footer>
© {% year %} Acme Co.
</footer>
➡️
footer.njk
Integration Example: Date from JavaScript
eleventyConfig.addShortcode("year",
() => `${new Date().getFullYear()}`
);
.eleventy.js

Key Features
Eleventy
Plugins
- included via the config
- provide shortcodes, filters
- other 11ty-aware transforms
Eleventy Plugins

Eleventy Plugins


Key Features
Flexible
Output
use `permalink` to change the file type and output location
Markdown
Nunjucks
Liquid
+7
➡️
.html
Flexible Output Example: Site RSS Feed
---
permalink: "feed/feed.xml"
eleventyExcludeFromCollections: true
---
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>{{ metadata.title }}</title>
<subtitle>{{ metadata.feed.subtitle }}</subtitle>
{% set absoluteUrl %}{{ metadata.feed.path | url | absoluteUrl(metadata.url) }}{% endset %}
<link href="{{ absoluteUrl }}" rel="self"/>
<link href="{{ metadata.url }}"/>
<updated>{{ collections.posts | rssLastUpdatedDate }}</updated>
<id>{{ metadata.feed.id }}</id>
<author>
<name>{{ metadata.author.name }}</name>
<email>{{ metadata.author.email }}</email>
</author>
{%- for post in collections.posts | reverse %}
{% set absolutePostUrl %}{{ post.url | url | absoluteUrl(metadata.url) }}{% endset %}
<entry>
<title>{{ post.data.title }}</title>
<link href="{{ absolutePostUrl }}"/>
<updated>{{ post.date | rssDate }}</updated>
<id>{{ absolutePostUrl }}</id>
<content type="html">{{ post.templateContent | htmlToAbsoluteUrls(absolutePostUrl) }}</content>
</entry>
{%- endfor %}
</feed>
feed/feed.njk
[
{
"title":"Page A",
"slug":"page-a"
},
{
"title":"Page B",
"slug":"page-b"
},
{
"title":"Page C",
"slug":"page-c"
}
]
➡️
functions/pages.json
Flexible Output Example: Page Data JSON
---
permalink: functions/pages.json
permalinkBypassOutputDir: true
eleventyExcludeFromCollections: true
---
[{% for pages in collections.pages %}
{
"title":"{{ pages.data.title | jsonTitle}}",
"slug":"{{ pages.data.title | slug}}"
}{% if forloop.last == false %},{% endif %}
{% endfor %}]
pagejson.njk
---
title: Page A
---
A nice page
➡️
---
title: Page B
---
A lovely page
---
title: Page C
---
The best page

Key Features
Active, Passionate Community







Key Features
Eleventy Starters


Key Features
Committed Creator:
Zach Leatherman

@eleven_ty
Build an Eleventy Site in 3 Minutes
Do you enjoy being a maker of the web?

Going Beyond Static With Eleventy
aka "How to Have Fun As A Web Maker Again"

Style Stage - Non-CMS Community Contributions

Style Stage - Non-CMS Community Contributions

Style Stage - Non-CMS Community Contributions
- Allows contributions w/o a CMS or auth setup
- PRs deployed to own preview branch (Netlify)
- GitHub provides auth and review interface
Style Stage - Non-CMS Community Contributions

Generators
- Produce an asset
- Provide an environment
Email Generator

➡️
Email Generator
eleventyConfig.addNunjucksAsyncFilter("emailHtml", (raw, callback) => {
if (meta.environment === "prod") {
callback(null, juice(raw));
} else {
callback(null, raw);
}
});
.eleventy.js
/*
* Sass styling
*/

---
subject: Hello New Subscriber!
heroImg: http://site.com/image.png
headline: Welcome to 11ty Rocks!
# ... and more
---
➡️
➡️
Web Component Generator
Web Component Generator

⚙️
Web Component Generator
aka "Exploiting layout functionality"
➡️
{%- set componentName = page.fileSlug %}
{%- set componentClass = page.fileSlug | createClass %}
{%- set componentScript %}components/{{componentName}}/script.js{% endset %}
{%- set componentCss %}components/{{componentName}}/style.css{% endset -%}
export class {{ componentClass }} extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
}
connectedCallback() {
const { shadowRoot } = this;
shadowRoot.innerHTML = `
<style>
* {
box-sizing: border-box;
}
{% include componentCss %}
</style>
{{ content | safe}}
`;
{% include componentScript %}
}
}
window.customElements.define("{{ componentName }}", {{ componentClass }});
_includes/component.njk
<h1 class="hello-world">
Hello World
</h1>
const hw = shadowRoot.querySelector(".hello-world");
setTimeout(() => {
hw.classList.add('hello-world__visible');
}, 1000);
➕
.hello-world {
color: var(--hw-color, white);
opacity: 0;
transition: opacity 180ms ease-in;
}
.hello-world__visible {
opacity: 1;
}
➕
components/hello-world.njk
_includes/components/hello-world/script.js
_includes/components/hello-world/style.css
CSS Houdini Worklet Generator
CSS Houdini Worklet Generator

🎩
CSS Houdini Worklet Generator

🎩
- Requires a secure/local server
- Worklets created with JS
- Paint API = current best support
CSS Houdini Worklet Generator

🎩

Generator's Example Worklet
CSS Houdini Worklet Generator

🎩

class HoudiniExample {
static get inputProperties() {
return [
"--houdiniExampleWidth",
"--houdiniExampleHeight",
"--houdiniExampleX",
"--houdiniExampleY",
"--houdiniExampleColor",
];
}
paint(ctx, size, properties) {
const width =
parseInt(properties.get("--houdiniExampleWidth")) || size.width;
const height =
parseInt(properties.get("--houdiniExampleHeight")) || size.height;
const x = parseInt(properties.get("--houdiniExampleX")) || 0;
const y = parseInt(properties.get("--houdiniExampleY")) || 0;
const color = String(properties.get("--houdiniExampleColor")) || "purple";
ctx.fillStyle = color;
ctx.fillRect(x, y, width, height);
}
}
registerPaint("houdiniExample", HoudiniExample);
worklet.js
CSS Houdini Worklet Generator

🎩

CSS Houdini Worklet Generator

CSS Houdini Worklet Generator


CSS Houdini Worklet Generator



CSS Houdini Worklet Generator


ButtonBuddy.dev

ButtonBuddy - 11ty + Parcel


💜

ButtonBuddy - 11ty + Parcel

`Static Site` !== `No Modern Client-Side JS`
Are you a little more excited to be a maker of the web?
learn new things
get feedback
grow your network
meet new awesome web makers
CSS Houdini Worklet Generator

CSS Houdini Worklet Generator

- Replace existing, older static setup
- Upgrade your playground
- Exploit 11ty's features
One more thing!
Publish presentation slides/notes on 11ty.Rocks
11ty.rocks
11ty.rocks
Going Beyond Static With Eleventy
Stephanie Eckles @5t3ph
11ty.Rocks • ModernCSS.dev • StyleStage.dev
Going Beyond Static With Eleventy
By Stephanie Eckles