Table of Contents

Image shortcode basics

Render a responsive image with one line of template code.

What comes back is more markup than you would want to write by hand, and the point of this guide is a feel for what the shortcode is doing on your behalf.

Baseline's image shortcode is a thin wrapper over Eleventy Image, and it's the only shortcode the plugin ships. A shortcode is just a template helper Eleventy invokes with {% image %} syntax.

Although you could place your media directory anywhere you'd like, Baseline's convention is src/media/. If you are used to have them under assets/img/, in Baseline that directory is reserved for global image assets.


What you will build

  • A page rendering a <picture> with avif, webp and jpeg sources.
  • Multiple widths of the same image emitted to /dist/media/.

Prerequisites

@11ty/eleventy-img. It is a peer dependency, so npm installs it alongside Baseline and you normally have it without asking. If it is missing, npm install @11ty/eleventy-img.


Add a sample image

Place any jpg or png image of your choice at src/media/. Rename it example.{jpg, png} for this tutorial. The format you start from matters less than what you put in alt.

Note that eleventy-img doesn't upscale your images; if your image is 640px only 320w + 640w of the default widths will be generated.

Use the shortcode in a page

Create src/content/pages/image-demo.md:

---
title: 'Image Shortcode Demo'
slug: 'image-demo'
description: 'Responsive image via Baseline shortcode.'
layout: 'layouts/base.njk'
---

This page displays an image using the {% raw %}`{% image {} %}`{% endraw %} shortcode.

{% image {
  src: "/media/example.jpg",
  alt: "A descriptive alt text for accessibility",
  caption: "Example image rendered responsively with the image shortcode."
} %}

The shortcode brings a set of defaults so you don't have to think about responsive widths or modern formats unless you want to:

  • Widths: [320, 640, 960, 1280, 1920]
  • Formats: ["avif", "webp", "jpeg"], in negotiation order, with jpeg last as the one every client can read
  • Output: ./dist/media/, URL: /media/. In a build the files are written to .cache/media/ first and copied across, so wiping dist does not cost you a re-encode.
  • Sizes: "auto" on lazy images, so the browser uses the real layout width, with "(max-width: 768px) 100vw, 768px" behind it for browsers that cannot
  • loading: "lazy", decoding auto-set, and a <figure> wrapper if caption is provided. Width and height are set by default.

The defaults aim to be cheap and safe, so anything expensive is opt-in. That is why 'auto', the full-size re-encode, is not in the width list: add it to widths when you want it. And the auto in sizes lets the browser use the width the image is really laid out at instead of trusting a number written here about your layout; browsers without it fall through to the rest of the list.

If a set suits your whole project, set it once at registration with media: { image: { widths, formats, sizes } } rather than on every call. See Image shortcode.

Paths are resolved from the project's input directory automatically: a leading-slash path like /media/example.jpg maps to src/media/example.jpg. A fully qualified path works too if that suits the project better.

  • Dot-relative paths (./src/media/example.jpg, ./example.jpg) will not resolve. Stick to a leading slash from src/, like /media/example.jpg.

The defaults cover most pages. Reach into the options when a particular image needs different handling. See the image shortcode reference for the full option list.

Run and verify

npm start
  • Open /image-demo/ and inspect the <picture> and <source> tags.
  • Check /dist/media/ for generated variants (named like example-a1b2c3-768w.avif; the hash is derived from the image content, which is what lets the build cache reuse them safely).

Production build

npm run build

Recheck /dist/media/ and the rendered HTML in dist/image-demo/index.html. A build pre-generates every variant up front, where npm start defers them to the first request.

Run it a second time and the images are not re-encoded: a build keeps its renditions in .cache/media/ and copies them over. See Caching for what that means on a deploy, and for the one case where you want to clear it by hand.

Notes

  • Keep alt meaningful. Captions are optional; alt text isn't.
  • Reasonably sized originals are kinder to the build. Very large inputs generate very large outputs.
  • The shortcode emits site-root-relative paths (/media/...). For an absolute image URL, e.g. to set as a page's ogImage share card, combine the path with settings.url from _data/settings.js.
  • In dev (when ELEVENTY_RUN_MODE=serve), the shortcode uses Eleventy Image's transformOnRequest mode, which defers image processing to the first browser request and keeps server startup snappy. During the content-graph pre-pass it uses statsOnly instead, which skips the same work but keeps the real image URLs, so your images are encoded once per build rather than twice. Builds pre-generate everything as usual. If either call fails, the shortcode retries without the flag.

Optional: use the Image Transform plugin

Prefer not to call a shortcode at all? Eleventy's Image Transform plugin processes every <img> and <picture> tag it finds. The trade-off is exactly that: it touches everything rather than the images you opt in to. Image transform is the recipe, and the Image plugin docs cover the configuration.


See also