---
title: "Markdown document title: where pandoc found it"
slug: markdown-document-title
excerpt: "Quoted pandoc output for a markdown document title set by percent lines sits under Percent lines under the markdown reader."
quickAnswer: "Both inputs are printed with cat in Two lead input files. Under Percent lines under the markdown reader, the fragment and selected lines from the full-page run are both quoted. Runs of that file under commonmark sit in The same lines under commonmark. A file holding one percent line is run by itself in A title line with no author or date. Runs on a file that opens with a heading are covered in A heading on line one. Output for the metadata option is quoted under Setting the title from the command line. A YAML header file and its runs appear in A title set in a YAML block. Grep steps for the title element are numbered in Checking the title element with grep."
keyTakeaways:
  - "Cat output for the two lead inputs is in Two lead input files."
  - "Read Percent lines under the markdown reader for the fragment run and the full-page run of the percent file."
  - "Commonmark results for that same file are collected in The same lines under commonmark."
  - "For a file whose top line is a heading, see A heading on line one."
  - "Steps to find and count title lines with grep are numbered in Checking the title element with grep."
publishedDate: 2026-10-21
dateModified: 2026-10-21
author: Bobby Huang
cluster: B
role: post
status: published
faq:
  - q: Will the commonmark reader pick up percent title lines?
    a: "Its runs on the percent file, along with what its extension list shows, are in The same lines under commonmark."
  - q: Can a top heading end up as the page title?
    a: "Two runs, one of them with a heading-level option, are quoted under A heading on line one."
  - q: How do I override the title when I run pandoc?
    a: "Under Setting the title from the command line, the metadata option is run on two of the test files."
  - q: Can a YAML header set the title instead?
    a: "Look in A title set in a YAML block for the YAML file and what pandoc wrote for it."
related:
  - what-is-front-matter
  - markdown-custom-heading-id
  - markdown-headings-anchor-links
---

Pandoc filled the title element of a full HTML page from four kinds of source in this test: a block of `%` lines, a YAML header, a top heading, and an option on the command line. The reader named after `-f`, plus the options added to the run, decided which source pandoc took.

Every result here came from a single Mac whose pandoc build is 3.8.3. You'll find the HTML that pandoc produced for a markdown document title, and nothing on how any program would present that HTML.

## Two lead input files

The lead test set has two inputs. Running `cat title-pct.md` printed three lines that start with `%`, an empty line, and one sentence:

```text
% Vendor review
% Jane Doe
% 2026-10-01

Body text.
```

Those three `%` lines hold a title, a name and a date. The date is a test value and nothing more.

Running `cat title-h1.md` printed a heading, a blank line and the same sentence:

```text
# Vendor review

Body text.
```

Both files close on that same sentence, so any change between their outputs traces back to the lines above it. Two further files, `title-only.md` and `title-yaml.md`, came from the extra test. Their `cat` output is printed in the sections that use them.

## Percent lines under the markdown reader

Inside pandoc, these `%` lines are called `pandoc_title_block`. It's a pandoc extension, and line 50 of the `markdown` extension list reads `+pandoc_title_block`, so the extension starts out enabled for that reader.

The first run left out `-s`:

```sh
pandoc -f markdown -t html title-pct.md
```

```html
<p>Body text.</p>
```

That fragment kept the sentence. Not one of the three `%` lines reached that output.

The second run added `-s`, which tells pandoc to write a whole page. That page runs past line 180, so grep picked out the ones that matter:

```sh
pandoc -f markdown -t html -s title-pct.md -o title-pct-markdown.html
grep -n -E '<title>|<h1 class="title"|class="author"|class="date"' title-pct-markdown.html
```

These are selected lines, each led by its line number in the page:

```text
9:  <title>Vendor review</title>
178:<h1 class="title">Vendor review</h1>
179:<p class="author">Jane Doe</p>
180:<p class="date">2026-10-01</p>
```

The first `%` line filled the title element and also an `<h1>` marked `class="title"`. Line two became a paragraph with `class="author"`, and line three one with `class="date"`.

To see the extension's part in this, the extra test switched it off with `-f markdown-pandoc_title_block`. The fragment then held:

```html
<p>% Vendor review % Jane Doe % 2026-10-01</p>
<p>Body text.</p>
```

## The same lines under commonmark

The list pandoc printed for `commonmark` runs 30 lines, and `pandoc_title_block` appears on none of them. When the extra test asked for it anyway with `-f commonmark+pandoc_title_block`, pandoc quit with exit status 23 and printed:

```text
The extension pandoc_title_block is not supported for commonmark.
Use --list-extensions=commonmark to list supported extensions.
```

Here is the plain fragment run:

```sh
pandoc -f commonmark -t html title-pct.md
```

```html
<p>% Vendor review % Jane Doe % 2026-10-01</p>
<p>Body text.</p>
```

All three `%` lines landed in one paragraph, with a space where each line break had been. Lines 3276 and 3277 of the CommonMark spec say that non-blank lines which can't be read as some other kind of block form a paragraph.

With `-s`, grep matched one of its four patterns:

```sh
pandoc -f commonmark -t html -s title-pct.md -o title-pct-commonmark.html
grep -n -E '<title>|<h1 class="title"|class="author"|class="date"' title-pct-commonmark.html
```

```text
7:  <title>title-pct</title>
```

So the title element held the file name minus its `.md` ending. The extra test also ran `grep -c '<h1 class="title">' title-pct-commonmark.html` and got `0`.

## A title line with no author or date

Running `cat title-only.md` printed one `%` line and the sentence:

```text
% Vendor review

Body text.
```

Under the `markdown` reader with `-s`, grep gave these selected lines:

```sh
pandoc -f markdown -t html -s title-only.md -o title-only.html
grep -n -E '<title>|<h1|class="author"|class="date"' title-only.html
```

```text
7:  <title>Vendor review</title>
176:<h1 class="title">Vendor review</h1>
```

No author line and no date line matched. One `%` line was enough to fill both the title element and the `<h1 class="title">` line.

## A heading on line one

With `-s` and nothing else, `title-h1.md` gave these selected lines:

```sh
pandoc -f markdown -t html -s title-h1.md -o title-h1.html
grep -n -E '<title>|<h1' title-h1.html
```

```text
7:  <title>title-h1</title>
175:<h1 id="vendor-review">Vendor review</h1>
```

The `#` heading stayed a body heading carrying an `id`, and the title element held the file name. Pandoc's heading IDs get their own write-up in [custom heading IDs](markdown-custom-heading-id.md).

Adding the pandoc option `--shift-heading-level-by=-1` changed both lines:

```sh
pandoc -f markdown -t html -s --shift-heading-level-by=-1 title-h1.md -o title-h1-shift.html
grep -n -E '<title>|<h1' title-h1-shift.html
```

```text
7:  <title>Vendor review</title>
176:<h1 class="title">Vendor review</h1>
```

Now the heading text sat in the title element, and the one `<h1>` grep found carried `class="title"` where the `id` used to be. Back in the first run, grep had also matched a single `<h1>` line, but that one held `id="vendor-review"` and no class.

## Setting the title from the command line

The pandoc option `--metadata` sets a value for the run. Here it was given `title=Override` on the heading file:

```sh
pandoc -f markdown -t html -s --metadata title=Override title-h1.md -o title-h1-meta.html
grep -n -E '<title>|<h1' title-h1-meta.html
```

```text
7:  <title>Override</title>
176:<h1 class="title">Override</h1>
178:<h1 id="vendor-review">Vendor review</h1>
```

Pandoc wrote `Override` into the title element and into a new `<h1 class="title">`. The file's own heading was still there at line 178, `id` and all.

The extra test gave the same option to the percent file:

```sh
pandoc -f markdown -t html -s --metadata title=Override title-pct.md -o title-pct-meta.html
grep -n -E '<title>|<h1|class="author"|class="date"' title-pct-meta.html
```

```text
9:  <title>Override</title>
178:<h1 class="title">Override</h1>
179:<p class="author">Jane Doe</p>
180:<p class="date">2026-10-01</p>
```

The option's value replaced the `%` title, while the author and date lines from the `%` block stayed in the page.

## A title set in a YAML block

A YAML header falls under another pandoc extension, `yaml_metadata_block`. The `markdown` list has it on at line 73, and the `commonmark` list has it off at line 30. For what the header is and how its keys are laid out, read [what front matter is](what-is-front-matter.md).

Running `cat title-yaml.md` printed:

```text
---
title: Vendor review
author: Jane Doe
---

Body text.
```

Under `markdown` with `-s`, grep gave these selected lines:

```sh
pandoc -f markdown -t html -s title-yaml.md -o title-yaml.html
grep -n -E '<title>|<h1|class="author"|class="date"' title-yaml.html
```

```text
8:  <title>Vendor review</title>
177:<h1 class="title">Vendor review</h1>
178:<p class="author">Jane Doe</p>
```

Without `-s`, the same reader wrote `<p>Body text.</p>` alone. Next, the extra test enabled that extension for `commonmark` as well, added `-s`, and wrote the page to `title-yaml-cm.html`. Grep returned those three lines again, with matching line numbers.

## Checking the title element with grep

The lead script or the extra one ran these steps inside the test folder. When you try them, replace the test names with yours.

1. Build a whole page with this command:
   `pandoc -f markdown -t html -s title-pct.md -o title-pct-markdown.html`
2. Show the title element and where it sits: `grep -n '<title>' title-pct-markdown.html`. Here it printed `9:  <title>Vendor review</title>`.
3. Count title headings: `grep -c '<h1 class="title">' title-pct-commonmark.html`. The output was `0`, with exit status 1 from grep. The same count on `title-h1-shift.html` printed `1`.
4. Compare what step 2 printed against the file name. Two pages here had the file name in the title element: `title-pct-commonmark.html` and `title-h1.html`.

Step 3 counts matching lines, so a `0` means grep found the pattern nowhere in that page. If those files also hold lists, [markdown bullet points](markdown-bullet-points.md) reports what pandoc wrote for them.

## Where Sashmark fits

The goal for Sashmark is editing that would happen right where you read, with no source mode to switch into. For its Round-Trip, the bar is that a save would leave every byte you did not change in its place. Next to that, Changes View should flag edits an agent made after your latest check, git repo or not.

It is in development and has not been released. The app itself has no AI features. See the [planned features](/features), the [help pages](/help) and the [roadmap](/roadmap) for where each part stands.

More at [sashmark.com](https://www.sashmark.com/).
