# Plugins

> Add textlane's Markdown and HTML plugins to the pipeline every page builds through.

Every page builds through [textlane](https://textlane.dev), a Rust Markdown and HTML pipeline. The `plugins` key of `htmlpress.yaml` adds textlane's own plugins to it, in two slots:

- `md` runs on a Markdown page's tree (mdast)
- `html` runs on every page's tree (hast), HTML and Markdown alike

**htmlpress.yaml**

```yaml
plugins:
  md:
    - name: md.shiftHeading
      options: { shift: 1 }
  html:
    - name: html.externalLinks
      options: { target: _blank }
```

## What a plugin can be

Each slot is a list whose entries take the same forms as textlane's `use`:

- **A name**: one of the plugins textlane ships, such as `html.externalLinks` or `md.toc`, with its defaults.
- **A name with options**: `{ name, options }`, the options as textlane documents them for that plugin.

Htmlpress is one binary, so a slot takes only the plugins built into it, and no JavaScript plugins as Livemark does. For markup of your own, add a [project component](/customization/overriding-escaping/) instead: a `:::name` directive or an `<htmlpress-name>` tag that your `components/<name>/` files fill.

## Where each slot runs

```text
Markdown page: parse → frontmatter, GFM, definition lists, math, directives
  → md plugins → heading ids, components → HTML
Every page:    parse → emoji, links, math → KaTeX → html plugins
  → heading slugs → path rewrites → syntax highlighting
```

- `md` plugins run **before** htmlpress renders directives as components, so they see every directive.
- `html` plugins run **before** heading slugs, so a heading a plugin adds gets an anchor and appears in the "On this page" outline. They run before syntax highlighting, so code blocks still hold their plain text.

## A plugin htmlpress already runs

Naming a plugin that is already in the pipeline, such as `md.gfm` or `html.slug`, reconfigures it rather than running it twice: your options are merged into htmlpress' own, as textlane's `use` merges a plugin used again. Where htmlpress sets the same option, its value wins, since its plugins are added after yours.

**htmlpress.yaml**

```yaml
plugins:
  html:
    - name: html.slug
      options: { prefix: doc- }
```

Here every generated heading id gets the `doc-` prefix, and headings still get their ids once.

## Errors and rebuilds

An unknown name or bad options fail the build with a `plugins.md` or `plugins.html` error, and so does a plugin whose tree does not fit its slot, such as `md.toHtml` under `html`. Editing `htmlpress.yaml` while `htmlpress start` runs rebuilds every page with the new plugins.

## See also

- [Configuration](/customization/configuration-file/): every other key.
- [textlane](https://textlane.dev): the plugins and their options.
