---
title: 'Content helpers'
description: 'How drafts, wikilinks, heading IDs, element attributes, and image handling work in Baseline, and the rules that keep content predictable.'
slug: 'content-helpers'
type: 'article'
date: 2026-05-02T00:00:00.000Z
lang: 'en'
url: 'https://www.eleventy-baseline.dev/docs/concept/content-helpers/'
---

This section covers the small but important pieces that keep content predictable as it scales.

Together, these helpers define how content moves through the system without adding friction or hidden behavior.

---

## Drafts

Any page with `draft: true` in front matter is dropped on `build` and kept on `serve`. The preprocessor is on automatically; you don't register it. Use it for in-progress pages you want to preview locally without shipping.

```yaml
---
title: 'Half-written thoughts'
draft: true
---
```

---

## Wikilinks

Forward links, MediaWiki-style. All resolved at render time, all combinable:

- `[[slug]]` links to the page with that slug. The link text defaults to the page's title.
- `[[slug#anchor]]` links to a heading on that page. The anchor is slugified for you.
- `[[slug:lang]]` hops to the translation in the named language (BCP47 code, e.g. `[[about:fr]]`).
- `[[slug|alias]]` sets custom link text. The pipe is the alias separator.

The forms compose. `[[about:fr#team|notre equipe]]` is valid. Misses (unknown slug, missing translation) render as the original literal text rather than a broken link, so a typo is visible without crashing the build.

Slugs are global within the default language. Wikilinks themselves are forward-only; the content-graph pre-pass does build a reverse index, exposed as `data._backlinks` per page and `_navigator.backlinks` site-wide, so authors can opt in to "what links here" surfaces without the wikilink syntax sprouting them automatically.

Curated cross-references still win over automatic ones in narrative prose.

---

### Where they work

Wikilinks are a markdown-it inline rule, so they resolve in `.md` body content only. They do not run in Nunjucks templates or in front matter values. If you need a link from a layout or a data field, write the URL directly.

---

## Heading IDs

Every heading in your Markdown gets a stable `id` attribute automatically. The id is the slugified heading text, so `## Implementation details` becomes `<h2 id="implementation-details">`. You can link to it directly with `#implementation-details`, and `_node.headings` carries the same id so a generated table of contents matches the anchors it points at.

Repeated headings dedup with WordPress-style numeric suffixes: the first stays `foo`, the second becomes `foo-2`, the third `foo-3`, and so on. Stable across builds for the same source order.

---

### Overriding an id

A manual id wins over the auto one. Use the attribute syntax described below:

{% raw %}

```markdown
## Implementation details {#impl}
```

{% endraw %}

Renders as `<h2 id="impl">`. Manual ids are also seeded into the dedup map, so a later heading with the same slugified text gets the next free name (`implementation-details` here, since `impl` does not collide).

---

### Why one source

Heading ids live in two places that need to agree: the rendered HTML you anchor links to, and the `headings[].id` field on the content graph that templates read for a TOC. They are assigned once in the markdown engine; the rendered HTML and the graph read the same id back. No drift between "the link" and "the table of contents entry".

---

## Element attributes

The {% raw %}`{#id .class key="value"}`{% endraw %} syntax attaches attributes to any block element. It runs through the upstream `markdown-it-attrs` plugin, which Baseline ships as a direct dependency.

{% raw %}

```markdown
## A section heading {#impl .lead}

A paragraph with a class. {.note}

![Alt text](/img/hero.jpg){#hero loading="eager"}
```

{% endraw %}

The attributes attach to the element that ended just before them. Useful for adding a class to a paragraph, anchoring a heading with a specific id, or marking an image so a transform can find it later.

Loaded under `safeUse`, so if you already wired `markdown-it-attrs` yourself with different options, your registration wins and Baseline's is skipped silently.

The same dedup applies to the heading-id and wikilinks plugins; you can layer your own markdown extensions without fighting Baseline's wiring.

---

## Images

The shortcode is Baseline's. The heavier transform isn't.

{% stepsBlock "compact" %}

- {% raw %}`{% image %}`{% endraw %} is always registered. `eleventy-img` is a peer dep that ships with Baseline.
- AVIF and WebP by default. No JPEG fallback. Modern browsers handle these and the file size difference is real.
- The HTML transform that rewrites `<img>` into responsive `<picture>` (`eleventyImageTransformPlugin`) is opt-in. You add it yourself if you want it. When it is present, the shortcode marks its own output with `eleventy:ignore` to avoid double-processing.

{% endstepsBlock %}

Alt text matters. The shortcode warns when it is missing (use an empty string for decorative images). The [[image-transform | image transform]] how-to walks you through the responsive pipeline.
