EnglishNederlandsFrançais Toggle theme

Eleventy Baseline

Start building your site, skip the recurring setup work.
Table of Contents

Head and NoIndex

Get a clean, correct <head> on every page with one placeholder and a settings file. By the end you'll have site-wide metadata, per-page head extras flowing through settings.head and front matter, and a proper canonical and robots story. Hreflang is covered in the [[multilngual-baseline-site | multilingual site tutorial]]. The placeholder is the only piece of HTML you write yourself.

The placeholder, <baseline-head>, is the element your layout puts on the page. Baseline swaps it for a sorted, deduplicated <head> at transform-time, the stage of the build where Eleventy hands rendered HTML to plugins for last-mile mutation. The data that fills it (title, description, canonical, links, scripts, hreflang) is gathered earlier, at cascade-time, when Eleventy is computing each page's data. Two stages, one placeholder.

What you will build

  • A page rendered with proper title and description.
  • Canonical and robots tags written automatically.
  • Site-wide and per-page head extras through link[], script[], meta[].
  • Noindex controls at both site and page level.
  • A neatly organised <head>, thanks to Capo.js.

Prerequisites

  • Baseline already installed and loaded, as in the simple site tutorial.
  • Set settings.url to your production URL (or leave localhost for local testing).
  • package.json with "type": "module" and the dev/build scripts:
    {
    	"name": "simple-baseline-site",
    	"type": "module",
    	"scripts": {
    		"start": "rimraf dist/ && npx @11ty/eleventy --serve",
    		"build": "rimraf dist/ && cross-env ELEVENTY_ENV=production npx @11ty/eleventy"
    	}
    }

1) Ensure Baseline is loaded

eleventy.config.js:

import baseline, { config as baselineConfig } from '@apleasantview/eleventy-plugin-baseline';
import settings from './src/_data/settings.js';

/** @param {import("@11ty/eleventy").UserConfig} eleventyConfig */
export default async function (eleventyConfig) {
	eleventyConfig.addPlugin(
		baseline(settings, {
			head: {
				titleSeparator: ' | ',
				showGenerator: true
			}
		})
	);
}

export const config = baselineConfig;

Two head options are worth knowing about:

  • titleSeparator controls how the page title and site title are joined. Defaults to |.
  • showGenerator adds a <meta name="generator"> tag. Off by default; flip it on if you want the credit visible in production.

2) Site-wide metadata

Update src/_data/settings.js. The fields below are the source of truth for what Baseline writes into every page's head:

export default {
	title: 'Baseline Head Demo',
	tagline: 'Head quickstart',
	url: process.env.URL || 'http://localhost:8080/',
	defaultLanguage: 'en',
	noindex: false,

	head: {
		link: [
			{ rel: 'stylesheet', href: '/assets/css/index.css' },
			{ rel: 'me', href: 'https://mastodon.social/@yourhandle' }
		],
		script: [{ src: '/assets/js/index.js', defer: true }],
		meta: [{ name: 'color-scheme', content: 'light dark' }]
	}
};

Each entry in link[], script[], and meta[] becomes an element on every page, alongside the defaults Baseline writes itself (charset, viewport, title, description, canonical, robots).

3) Layout with the placeholder

Create src/_includes/layouts/base.njk. Baseline replaces <baseline-head></baseline-head> with the rendered <head> at build time. It sits as a sibling of <body>, never inside a <head> of your own. If the placeholder is missing, Baseline quietly skips the replacement and nothing is injected. Refer to the minimal layout in the simple site tutorial.

4) Page front matter

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

---
title: 'Head Demo'
slug: 'head-demo'
description: 'A page showing Baseline head defaults.'
layout: 'layouts/base.njk'
---

This page uses Baseline's head defaults for canonical and robots. The title and description in the front matter become the rendered `<title>` and `<meta name="description">`.

5) Per-page head overrides

A page's own front matter can extend or override the site-wide head. Add this block to src/content/pages/head-demo.md:

head:
  meta:
    - { name: 'description', content: 'Override description for this page' }
  link:
    - { rel: 'author', href: 'https://yourdomain.com' }

Baseline resolves the canonical URL in a fallback chain. It first looks at front matter head.link[rel=canonical]. If absent, it computes one from page.url, settings.url, and pathPrefix. If settings.url is missing, it writes nothing. Supplying canonical in front matter will not work Baseline computes it for you.

For Open Graph or Twitter card meta tags, add them as plain head.meta[] entries. Baseline doesn't render OG or Twitter shells automatically yet; the surface is staged but not wired in this release.

6) Noindex (site-wide and per-page)

Three knobs, in widening order of scope:

  • Site-wide: set noindex: true in _data/settings.js. Every page gets a robots noindex tag, and the sitemap is skipped entirely.
  • Per-page: set noindex: true in front matter. The page renders a robots noindex tag and drops out of the sitemap.
  • Sitemap-only: set sitemap: { ignore: true } in front matter. The page renders normally; only the sitemap entry is removed.

The relationship is deliberate: noindex is the broader signal (don't index, don't list), sitemap.ignore is the narrow one (just don't list).

7) Run and inspect

npm start
  • Open /head-demo/ (default http://localhost:8080/head-demo/).
  • View source. Confirm the placeholder is gone, the canonical (or your override) is in, and the defaults for description and robots are rendered.
  • Check dist/sitemap.xml while dev runs. The page should appear unless noindex is true.

8) Production build

Change URL in .env to an absolute URL. On a deployed site that's your real production URL; for this exercise, any absolute URL (e.g. https://www.example.com/) works to verify the output. Then run:

npm run build
  • Inspect dist/head-demo/index.html for the rendered head.
  • Confirm dist/sitemap.xml includes or excludes the page in line with noindex.
  • Reset URL in .env to "http://localhost:8080/".

Next steps