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
titleanddescription. - 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.urlto your production URL (or leave localhost for local testing). package.jsonwith"type": "module"and thedev/buildscripts:{ "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:
titleSeparatorcontrols how the page title and site title are joined. Defaults to|.showGeneratoradds 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: truein_data/settings.js. Every page gets arobotsnoindex tag, and the sitemap is skipped entirely. - Per-page: set
noindex: truein front matter. The page renders arobotsnoindex 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.xmlwhile dev runs. The page should appear unlessnoindexis 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.htmlfor the rendered head. - Confirm
dist/sitemap.xmlincludes or excludes the page in line withnoindex. - Reset
URLin.envto "http://localhost:8080/".
Next steps
- Add custom
head.link[],head.script[], orhead.meta[]entries through_data/settings.jsor per-page front matter. - For the full multilingual setup, see the multilingual site tutorial and the head module reference.
Previous: Image Shortcode Basics
Next: Sitemaps and Drafts