Quick Start: Eleventy Shortcodes for Responsive Images & Inline SVG

Quick Start: Eleventy Shortcodes for Responsive Images & Inline SVG

Quick start to production-ready Eleventy shortcodes: responsive images with @11ty/eleventy-img and inline SVG helpers you can copy-paste and use immediately.

This guide shows how to add two production-ready shortcodes to Eleventy (ESM): a responsive image helper using @11ty/eleventy-img and an inline SVG helper that lets you inject CSS classes.

An AI generated image

Quick Start

Follow these steps to get ready-to-use shortcodes in minutes:

  1. Install dependency

    Terminal window
    npm i @11ty/eleventy-img
  2. Create the shortcodes module at eleventy/shortcodes/media.js (see below)

  3. Register it in eleventy.config.js and rebuild

  4. Use {% image %} for responsive images and {% svg %} for inline SVG in your Nunjucks templates

What you get

The {% image %} shortcode outputs a <picture> element with AVIF/WebP sources, responsive widths, lazy loading, and decoding hints—all preconfigured for production use.

Prerequisites

  • Eleventy v2+ or v3 with ESM config.
  • Nunjucks templates (examples use {% %} tags).
  • Project layout with assets under src/.

Example folders:

src/
assets/
images/
icons/

Install

Terminal window
npm i @11ty/eleventy-img

Shortcodes module

Create eleventy/shortcodes/media.js:

import path from "node:path";
import fs from "node:fs";
import Image from "@11ty/eleventy-img";
/** Responsive image (async) */
async function imageShortcode(src, alt, sizes = "100vw") {
if (!alt) throw new Error(`Missing alt for ${src}`);
// Normalize to src/assets/images/
const normalized = src.replace(/^\/?src\/assets\/images\/?/, "");
const resolved = path.resolve("src/assets/images", normalized);
const metadata = await Image(resolved, {
widths: [320, 640, 960, 1280, null], // null => original width
formats: ["avif", "webp"], // add "jpeg" if you want a fallback
outputDir: "./_site/img/",
urlPath: "/img/",
});
return `<figure>${Image.generateHTML(metadata, {
alt,
sizes,
loading: "lazy",
decoding: "async",
})}</figure>`;
}
/** Inline SVG with optional class */
function svgShortcode(svgPath, className = "") {
const rel = svgPath.replace(/^\/?src\/?/, ""); // keep paths under src/
const fullPath = path.join(process.cwd(), "src", rel);
const svg = fs.readFileSync(fullPath, "utf8");
if (!className) return svg;
// Append or set class on the opening <svg ...>
const hasClass = /<svg([^>]*?)\sclass="([^"]*)"/i.test(svg);
if (hasClass) {
return svg.replace(
/<svg([^>]*?)\sclass="([^"]*)"([^>]*)>/i,
(_m, pre, cls, post) => `<svg${pre} class="${cls} ${className}"${post}>`
);
}
return svg.replace(/<svg([^>]*)>/i, `<svg$1 class="${className}">`);
}
export default (cfg) => {
cfg.addNunjucksAsyncShortcode("image", imageShortcode);
cfg.addNunjucksShortcode("svg", svgShortcode);
};

Register in Eleventy config

In eleventy.config.js (ESM):

import mediaShortcodes from "./eleventy/shortcodes/media.js";
export default function(eleventyConfig) {
eleventyConfig.addPlugin(mediaShortcodes);
}

Usage in Nunjucks

Responsive image (async shortcode):

{% image "hero/cover.jpg", "Site cover image", "(min-width: 768px) 75vw, 100vw" %}

Inline SVG with a custom class:

{% svg "assets/icons/github.svg", "icon-lg text-neutral-700" %}

Alternative: expression style

If you prefer {{ ... }} output for SVG, also register:

// in the plugin function
cfg.addShortcode("svg", svgShortcode);

Then:

{{ svg("assets/icons/github.svg", "icon-lg") | safe }}

Troubleshooting and notes

  • “Unable to call ‘svg’…” means you registered with addShortcode but used {% svg %}. Use addNunjucksShortcode for tag syntax.
  • Paths: keep inputs relative to src/…. The module normalizes src/assets/images/... automatically for images and src/... for SVGs.
  • Accessibility: alt is required. Use empty alt only for decorative images.
  • Fallbacks: if you need a bitmap fallback, add "jpeg" to formats.
  • Caching: @11ty/eleventy-img caches processed assets. Commit the cache if you want stable builds in CI.

Additional tips:

  • ESM vs CJS configs: This example assumes ESM. If you are on CommonJS, adapt imports/exports accordingly.
  • Windows paths: Prefer path.resolve and avoid hardcoded backslashes. The provided code handles normalization.
  • External URLs: The shortcode expects local files. For remote images, download them during build or provide a local copy.

Next steps

Want automatic optimization for standard Markdown images (no shortcode required)? Continue with the advanced guide:

Minimal CSS example

.icon-lg { width: 1.5rem; height: 1.5rem; display: inline-block; }

Commit message template

Terminal window
feat(shortcodes): add responsive image and inline SVG helpers (Nunjucks, ESM)