eleventy-bricks

A collection of helpful utilities and filters for Eleventy (11ty).

Installation

npm install @anydigital/eleventy-bricks

Usage

You can use this library in two ways:

Option 1: As a Plugin

Import and use the entire plugin. You can configure which helpers to enable using the options parameter:

ES Modules:

import eleventyBricks from "@anydigital/eleventy-bricks";

export default function(eleventyConfig) {
  eleventyConfig.addPlugin(eleventyBricks, {
    mdAutoRawTags: true  // Enable mdAutoRawTags preprocessor (default: false)
  });
  
  // Your other configuration...
}

CommonJS:

const eleventyBricks = require("@anydigital/eleventy-bricks");

module.exports = function(eleventyConfig) {
  eleventyConfig.addPlugin(eleventyBricks, {
    mdAutoRawTags: true  // Enable mdAutoRawTags preprocessor (default: false)
  });
  
  // Your other configuration...
};

Note: The CommonJS wrapper uses dynamic imports internally and returns async functions. Eleventy's addPlugin() method handles this automatically.

Option 2: Import Individual Helpers (Recommended)

Import only the specific helpers you need without using the plugin:

ES Modules:

import { bricks, mdAutoRawTags, mdAutoNl2br, setAttrFilter, byAttrFilter, siteData } from "@anydigital/eleventy-bricks";

export default function(eleventyConfig) {
  bricks(eleventyConfig);
  mdAutoRawTags(eleventyConfig);
  mdAutoNl2br(eleventyConfig);
  setAttrFilter(eleventyConfig);
  byAttrFilter(eleventyConfig);
  siteData(eleventyConfig);
  
  // Your other configuration...
}

CommonJS:

const { bricks, mdAutoRawTags, mdAutoNl2br, setAttrFilter, byAttrFilter, siteData } = require("@anydigital/eleventy-bricks");

module.exports = async function(eleventyConfig) {
  await bricks(eleventyConfig);
  await mdAutoRawTags(eleventyConfig);
  await mdAutoNl2br(eleventyConfig);
  await setAttrFilter(eleventyConfig);
  await byAttrFilter(eleventyConfig);
  await siteData(eleventyConfig);
  
  // Your other configuration...
};

Note: When using CommonJS with individual helpers, the config function must be async and each helper must be awaited, as the CommonJS wrapper uses dynamic imports internally.

Configuration Options

When using the plugin (Option 1), you can configure which helpers to enable:

Option Type Default Description
bricks boolean false Enable the bricks system for dependency management
mdAutoRawTags boolean false Enable the mdAutoRawTags preprocessor for Markdown files
mdAutoNl2br boolean false Enable the mdAutoNl2br preprocessor to convert
to <br> tags
setAttrFilter boolean false Enable the setAttr filter for overriding object attributes
byAttrFilter boolean false Enable the byAttr filter for filtering collections by attribute values
siteData boolean false Enable site.year and site.isProd global data

Example:

eleventyConfig.addPlugin(eleventyBricks, {
  bricks: true,
  mdAutoRawTags: true,
  byAttrFilter: true,
  siteData: true
});

Available 11ty Helpers

bricks

A dependency management system for Eleventy that automatically collects and injects CSS and JavaScript dependencies (both external and inline) per page. This allows brick components to declare their dependencies, and the system will inject them in the correct location in your HTML.

Why use this?

When building reusable components (bricks) in Eleventy, you often need to include CSS and JavaScript dependencies. Instead of manually adding these to every page, bricks automatically:

How it works:

  1. Use the bricksDependencies shortcode in your base template to mark where dependencies should be injected
  2. Use the brick shortcode to register and render brick components that declare their dependencies
  3. The system automatically collects all dependencies and injects them when the page is built

Usage:

  1. Enable bricks in your Eleventy config:
import { bricks } from "@anydigital/eleventy-bricks";

export default function(eleventyConfig) {
  bricks(eleventyConfig);
  // Or use as plugin:
  // eleventyConfig.addPlugin(eleventyBricks, { bricks: true });
}
  1. Add the bricksDependencies shortcode in your base template (typically in the <head> section):
<head>
  <meta charset="UTF-8">
  <title>My Site</title>
  {% bricksDependencies [
    ... (global dependencies can be set here) ...
  ] %}
  <!-- Other head content -->
</head>
  1. Create brick components that declare their dependencies:
// myBrick.js
export default {
  dependencies: [
    'https://cdn.example.com/library.css',
    'https://cdn.example.com/library.js'
  ],
  style: `
    .my-component { color: blue; }
  `,
  script: `
    console.log('Component initialized');
  `,
  render: function() {
    return '<div class="my-component">Hello World</div>';
  }
};
  1. Use the brick shortcode in your templates:
{% set myBrick = require('./myBrick.js') %}
{% brick myBrick %}

Brick Component Structure:

A brick component is a JavaScript object with the following optional properties:

Output:

The system will automatically inject all dependencies in the order they were registered:

<head>
  <meta charset="UTF-8">
  <title>My Site</title>
  <link rel="stylesheet" href="https://cdn.example.com/library.css">
  <style>.my-component { color: blue; }</style>
  <script src="https://cdn.example.com/library.js"></script>
  <script>console.log('Component initialized');</script>
  <!-- Other head content -->
</head>

Features:

mdAutoRawTags

Prevents Nunjucks syntax from being processed in Markdown files by automatically wrapping {{, }}, {%, and %} with {% raw %} tags.

Why use this?

When writing documentation or tutorials about templating in Markdown files, you often want to show Nunjucks/Liquid syntax as literal text. This preprocessor automatically escapes these special characters so they display as-is instead of being processed by the template engine.

Usage:

  1. Enable mdAutoRawTags in your Eleventy config:
import { mdAutoRawTags } from "@anydigital/eleventy-bricks";

export default function(eleventyConfig) {
  mdAutoRawTags(eleventyConfig);
  // Or use as plugin:
  // eleventyConfig.addPlugin(eleventyBricks, { mdAutoRawTags: true });
}

Example:

Before mdAutoRawTags, writing this in Markdown:

Use {{ variable }} to output variables.

Would try to process {{ variable }} as a template variable. With mdAutoRawTags, it displays exactly as written.

mdAutoNl2br

Automatically converts \n sequences to <br> tags in Markdown content. This is particularly useful for adding line breaks inside Markdown tables where standard newlines don't work.

Why use this?

Markdown tables don't support multi-line content in cells. By using \n in your content, this preprocessor will convert it to <br> tags, allowing you to display line breaks within table cells and other content.

Usage:

  1. Enable mdAutoNl2br in your Eleventy config:
import { mdAutoNl2br } from "@anydigital/eleventy-bricks";

export default function(eleventyConfig) {
  mdAutoNl2br(eleventyConfig);
  // Or use as plugin:
  // eleventyConfig.addPlugin(eleventyBricks, { mdAutoNl2br: true });
}

Example:

In your Markdown file:

| Column 1 | Column 2 |
|----------|----------|
| Line 1\nLine 2\nLine 3 | Another cell\nWith multiple lines |

Will render as:

<td>Line 1<br>Line 2<br>Line 3</td>
<td>Another cell<br>With multiple lines</td>

Note: This processes literal \n sequences (backslash followed by 'n'), not actual newline characters. Type \n in your source files where you want line breaks.

setAttr

A filter that creates a new object with an overridden attribute value. This is useful for modifying data objects in templates without mutating the original.

Why use this?

When working with Eleventy data, you sometimes need to modify an object's properties for a specific use case. The setAttr filter provides a clean way to create a modified copy of an object without affecting the original.

Usage:

  1. Enable setAttr in your Eleventy config:
import { setAttrFilter } from "@anydigital/eleventy-bricks";

export default function(eleventyConfig) {
  setAttrFilter(eleventyConfig);
  // Or use as plugin:
  // eleventyConfig.addPlugin(eleventyBricks, { setAttrFilter: true });
}
  1. Use the filter in your templates:
{# Create a modified version of a page object #}
{% set modifiedPage = page | setAttr('title', 'New Title') %}

<h1>{{ modifiedPage.title }}</h1>
<p>Original title: {{ page.title }}</p>

Parameters:

Returns:

A new object with the specified attribute set to the given value. The original object is not modified.

Features:

Examples:

{# Override a single attribute #}
{% set updatedPost = post | setAttr('featured', true) %}

{# Chain multiple setAttr filters #}
{% set modifiedPost = post 
  | setAttr('category', 'blog') 
  | setAttr('priority', 1) 
%}

{# Use in loops #}
{% for item in collection %}
  {% set enhancedItem = item | setAttr('processed', true) %}
  {# ... use enhancedItem ... #}
{% endfor %}

byAttr

A filter that filters collection items by attribute value. It checks if an item's attribute matches a target value. If the attribute is an array, it checks if the array includes the target value.

Why use this?

When working with Eleventy collections, you often need to filter items based on front matter data. The byAttr filter provides a flexible way to filter by any attribute, with special handling for array attributes (like tags).

Usage:

  1. Enable byAttr in your Eleventy config:
import { byAttrFilter } from "@anydigital/eleventy-bricks";

export default function(eleventyConfig) {
  byAttrFilter(eleventyConfig);
  // Or use as plugin:
  // eleventyConfig.addPlugin(eleventyBricks, { byAttrFilter: true });
}
  1. Use the filter in your templates:

Filter by exact attribute match:

{# Get all posts with category 'blog' #}
{% set blogPosts = collections.all | byAttr('category', 'blog') %}

{% for post in blogPosts %}
  <h2>{{ post.data.title }}</h2>
{% endfor %}

Filter by array attribute (tags):

{# Get all posts that include 'javascript' tag #}
{% set jsPosts = collections.all | byAttr('tags', 'javascript') %}

{% for post in jsPosts %}
  <h2>{{ post.data.title }}</h2>
{% endfor %}

Parameters:

Features:

Examples:

Front matter:

---
title: My Post
category: blog
tags: [javascript, tutorial, beginner]
priority: 1
---

Template usage:

{# Filter by category #}
{% set blogPosts = collections.all | byAttr('category', 'blog') %}

{# Filter by tag (array) #}
{% set jsTutorials = collections.all | byAttr('tags', 'javascript') %}

{# Filter by numeric value #}
{% set highPriority = collections.all | byAttr('priority', 1) %}

{# Chain filters #}
{% set recentBlogPosts = collections.all | byAttr('category', 'blog') | reverse | limit(5) %}

siteData

Adds global site data to your Eleventy project, providing commonly needed values that can be accessed in all templates.

Why use this?

Many websites need access to the current year (for copyright notices) and environment information (to conditionally enable features based on production vs development). This helper provides these as global site data without manually setting them up.

Usage:

  1. Enable siteData in your Eleventy config:
import { siteData } from "@anydigital/eleventy-bricks";

export default function(eleventyConfig) {
  siteData(eleventyConfig);
  // Or use as plugin:
  // eleventyConfig.addPlugin(eleventyBricks, { siteData: true });
}
  1. Use the global data in your templates:

Current Year:

<footer>
  <p>&copy; {{ site.year }} Your Company Name. All rights reserved.</p>
</footer>

Environment Check:

{% if site.isProd %}
  <!-- Production-only features -->
  <script async src="https://www.googletagmanager.com/gtag/js?id=GA_TRACKING_ID"></script>
{% else %}
  <!-- Development-only features -->
  <div class="dev-toolbar">Development Mode</div>
{% endif %}

Available Data:

Features:

Examples:

{# Copyright notice #}
<p>Copyright &copy; {{ site.year }} My Site</p>

{# Conditional loading of analytics #}
{% if site.isProd %}
  <script src="/analytics.js"></script>
{% endif %}

{# Different behavior in dev vs prod #}
{% if site.isProd %}
  <link rel="stylesheet" href="/css/styles.min.css">
{% else %}
  <link rel="stylesheet" href="/css/styles.css">
  <script src="/live-reload.js"></script>
{% endif %}

Additional Exports

The plugin also exports the following for advanced usage:

Starter Configuration Files

The package includes pre-configured starter files in node_modules/@anydigital/eleventy-bricks/src/ that you can symlink to your project for quick setup:

Available Starter Files

eleventy.config.js

A fully-configured Eleventy config file with:

Required dependencies:

npm install @11ty/eleventy-navigation markdown-it markdown-it-anchor js-yaml minimist

Symlink to your project:

ln -s node_modules/@anydigital/eleventy-bricks/src/eleventy.config.js eleventy.config.js

admin/index.html

A ready-to-use Sveltia CMS admin interface for content management.

Symlink to your project:

mkdir -p admin
ln -s ../node_modules/@anydigital/eleventy-bricks/src/admin/index.html admin/index.html

Benefits of Symlinking

Alternative: Copy Files

If you prefer to customize the configurations extensively, you can copy the files instead:

cp node_modules/@anydigital/eleventy-bricks/src/eleventy.config.js .
mkdir -p admin
cp node_modules/@anydigital/eleventy-bricks/src/admin/index.html admin/

CLI Helper Commands

After installing this package, the download-files command becomes available:

download-files

A CLI command that downloads external files to your project based on URLs specified in your package.json.

Usage:

  1. Add a _downloadFiles field to your project's package.json with URL-to-path mappings:
{
  "_downloadFiles": {
    "https://example.com/library.js": "src/vendor/library.js",
    "https://cdn.example.com/styles.css": "public/css/external.css"
  }
}
  1. Run the download command:
npx download-files

Options:

# Download all files to a specific directory
npx download-files --output public

Features:

Use Cases:

Requirements

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.