Static Site Generators

Alembic is designed to be compiled up-front to reduce the amount of JavaScript you need to ship to users. There are specific bits of the library for achieving this and there is also an Eleventy plugin too.



  • Node.js v18+
  • npm v7+

Then install Alembic with NPM:

npm install --save-dev @openlab/alembic

These CSS variables need to be set to use Alembic:

:root {
/* A colour for the foremost thing, like the text in a box */
--color-foreground: black;

/* A colour for the backmost thing, like the background of a box */
--color-background: white;

/* The thickness of a border, like a box. Perhaps use a modular scale variable */
--border-thin: 0.2rem;

/* The maximum width of text on the body of a page, to make it more readable */
--measure: 60ch;

Eleventy plugin

If you're using Eleventy 1.x, it's super easy to install!

Insert this into your existing .eleventy.js:

const { eleventyAlembic } = require('@openlab/alembic/11ty')

module.exports = function (eleventyConfig) {

return // ...

The plugin does two things. First it adds a eleventy.after event which creates alembic/style.css and alembic/script.js in your site output folder.

This only works for sites that are at the top-level of a domain, not ones in a subdirectory. Comment on #50 if interested in subdirectories.

Second it adds a transform for any HTML file to generate any custom element styles and insert them back into the document. You need to add one of both of these comments to you HTML template/layout for this to take effect. The plugin will replace the comments with the generated styles/scripts.

<!-- @openlab/alembic inject-css --> tells the plugin where to put styles. It will put generated custom element styles and a link to the alembic/style.css mentioned above where this comment is.

<!-- @openlab/alembic inject-js --> tells the plugin where to put scripts. It will link to the alembic/script.js mentioned above here, it's only needed if you want dynamic styles on your pages. This is often useful for development but might not be needed for production builds.

For example:

<!DOCTYPE html>
<!-- @openlab/alembic inject-css -->
<!-- @openlab/alembic inject-js -->

Eleventy options

You can pass these options to eleventyAlembic to configure how it works:

  • skipBaseStyles=false Don't generate or insert the CSS styles
  • skipBaseScripts=false Don't generate or insert the scripts
  • useLabcoat=false (Unstable) Use labcoat instead of the base styles

and you use them like this:

eleventyConfig.addPlugin(eleventyAlembic, {
skipBaseStyles: true,


Alembic provides the tools to hook it up to a static site generator.

The methods you'll be interested in are: processHtml, getStyles, getBaseStyles and getBaseScripts which you can import from the "tools" script. These are the same tools the Eleventy plugin use.

import {
} from '@openlab/alembic/tools.js'


processHtml takes a HTML string, looks through it for Alembic usage and modifies the HTML to include custom element styles (e.g. for the layouts).

You can optionally provide options to inject extra HTML into the inputHtml too at either the script or style location. This is useful to automatically add the Alembic base styles / scripts from getBaseStyles and getBaseScripts. Your build process could write these files somewhere then make sure they are linked to from the HTML here.

import { processHtml } from '@openlab/alembic'

const options = {
extraStyles: [`<link rel="stylesheet" href="/alembic/style.css">`],
extraScripts: [`<script type="module" src="/alembic/script.js"></script>`],

processHtml('<html>...', options)

You control where the styles and scripts are injected using a special HTML comments <!-- @openlab/alembic inject-css --> and <!-- @openlab/alembic inject-js -->. You opt in to those features by adding the comment to your HTML.


getStyles takes a HTML string, looks through it for Alembic usage and returns the styles to satisfy it. This is useful for SSR when you have something that has already generated style ids on custom elements and need to get the styles for a whole document in one go.

import { getStyles } from '@openlab/alembic'

getStyles('<html>...') // Map<string, string>


Get the base styles for non-dynamic Alembic. Useful for creating a stylesheet during SSG to be linked to from a HTML document.

const sourcecode = await getBaseStyles()


Get the scripts as a string to run Alembic in-browser. Useful for creating a script during SSG to be linked to from a HTML document.

const sourcecode = await getBaseScripts()