---
title: "Markdown smart quotes: pandoc's smart extension tested"
slug: markdown-smart-quotes
excerpt: "Four pandoc reader settings, one quote test file: the section Turning smart on and off in pandoc shows the output pandoc gave."
quickAnswer: "For markdown smart quotes, start with the section Turning smart on and off in pandoc, which runs one quote test through four pandoc reader settings. The section Double quotes, single quotes and apostrophes shows which references pandoc gave. The section Decades, dashes and three dots covers a decade like '90s plus dash and dot input. The section Code spans and backslashes shows two ways a quote stayed straight in this test. Under Checking a file for smart quotes, there are numbered steps you can run."
keyTakeaways:
  - "The section What the CommonMark spec says about quotes reports a word search of the spec and the escape rule that covers quote marks."
  - "The section Turning smart on and off in pandoc shows a table of four reader settings run on one test file."
  - "Under Decades, dashes and three dots, you can see what pandoc gave for '90s, two hyphens, three hyphens and three dots."
  - "The section Curly quotes typed into the source tests a file that already holds curly quotes with smart turned off."
  - "The section Checking a file for smart quotes lists the commands for checking a reader, its output and the file's bytes."
publishedDate: 2026-10-20
dateModified: 2026-10-20
author: Bobby Huang
cluster: B
role: post
status: published
faq:
  - q: What makes straight quotes turn curly?
    a: "Under Turning smart on and off in pandoc, a table shows which reader settings curled the quotes in this test."
  - q: Can one quote stay straight with smart on?
    a: "Under Code spans and backslashes, two cases kept a quote straight with smart on."
  - q: Does turning smart off straighten curly quotes I typed?
    a: "Under Curly quotes typed into the source, the test shows the output pandoc gave."
related:
  - markdown-escape-characters
  - markdown-code-blocks
  - markdown-invisible-characters
---

You typed a plain double quote in a Markdown file. The HTML output showed a curved one instead, and a pair of hyphens turned into a single dash. Or the reverse happened: you wanted curved quotes and got the straight marks you typed.

In pandoc, this is the `smart` extension. This post runs a small set of test files through four pandoc reader settings and shows the output, so you can tell which setting gave which result.

## The test setup

The tests ran once, on one Mac, using pandoc 3.8.3. The six main test files each hold one line made with `printf`, using plain ASCII quotes, hyphens and dots. Each of the six went through four reader settings:

- `-f commonmark`
- `-f commonmark+smart`
- `-f markdown`
- `-f markdown-smart`

Each run used `-t html --ascii`. With `--ascii`, pandoc wrote the curved quotes, dashes and dots in these tests as numeric references, such as `&#x201C;`. That keeps the output readable here, since this page holds ASCII only.

## What the CommonMark spec says about quotes

Searching the text of the CommonMark spec, version 0.31.2, for the words "smart", "curly" and "typographic" turned up none of them. The spec does list both quote marks, `"` and `'`, as ASCII punctuation characters, and its backslash escape rule lets you escape any character in that group. The [escape characters guide](markdown-escape-characters.md) covers that rule in full.

So in this test, any change from straight to curved came from pandoc's `smart` extension, set by the reader name and the `+` or `-` after it.

## Turning smart on and off in pandoc

Pandoc can list a reader's extensions with a plus or minus sign in front of the name:

~~~sh
pandoc --list-extensions=commonmark | grep smart
pandoc --list-extensions=markdown | grep smart
~~~

Pandoc 3.8.3 printed `-smart` for `commonmark` and `+smart` for `markdown`. The minus means off by default and the plus means on by default. Adding `+smart` to a reader name turns it on, and `-smart` turns it off.

Here is the test file `sq-double.md`:

~~~markdown
Jane said "Doe Holdings" won't wait.
~~~

The four runs gave two different results:

| Reader setting | Output |
|---|---|
| `commonmark` | `<p>Jane said "Doe Holdings" won't wait.</p>` |
| `commonmark+smart` | `<p>Jane said &#x201C;Doe Holdings&#x201D; won&#x2019;t wait.</p>` |
| `markdown` | `<p>Jane said &#x201C;Doe Holdings&#x201D; won&#x2019;t wait.</p>` |
| `markdown-smart` | `<p>Jane said "Doe Holdings" won't wait.</p>` |

Both settings with `smart` on curved the quotes. Both settings with it off left them as typed. Plain `markdown` curved them with no flag at all, since `smart` is on by default in that reader.

## Double quotes, single quotes and apostrophes

In the `sq-double.md` output above, `&#x201C;` sits where the quote opens and `&#x201D;` where it closes. The apostrophe in `won't` became `&#x2019;`.

The file `sq-single.md` holds `Jane's 'draft' plan`. With `smart` on, both `commonmark+smart` and `markdown` gave this:

~~~html
<p>Jane&#x2019;s &#x2018;draft&#x2019; plan</p>
~~~

The single quote that opens `draft` became `&#x2018;`. The one that closes it and the apostrophe in `Jane's` both became `&#x2019;`, the same reference. With `smart` off, the line came back exactly as typed.

In this test, without `--ascii`, pandoc wrote the curved marks as real characters. An `od -c` dump of the `commonmark+smart` output for `sq-double.md` showed each one as a multi-byte character.

## Decades, dashes and three dots

The `smart` extension touches more than quotes. The file `sq-decade.md` holds `The '90s plan`. With `smart` on, pandoc gave `<p>The &#x2019;90s plan</p>`: the quote before the digits became `&#x2019;`, the same reference it used for the apostrophe in `won't`.

The file `sq-dashes.md` holds `Pages 3--5 of the plan---Jane Doe...` and gave this with `smart` on:

~~~html
<p>Pages 3&#x2013;5 of the plan&#x2014;Jane Doe&#x2026;</p>
~~~

Two hyphens became `&#x2013;`, three hyphens became `&#x2014;`, and three dots became `&#x2026;`. With `smart` off, under `commonmark` or `markdown-smart`, the hyphens and dots stayed as typed.

## Code spans and backslashes

Two kinds of input kept straight quotes even with `smart` on.

The first is a code span. The file `sq-code.md` holds this line:

~~~markdown
Run `echo "Doe"` and keep "Jane".
~~~

With `smart` on, pandoc gave `<code>echo "Doe"</code>` with straight quotes, while the quotes around `Jane` outside the code became `&#x201C;` and `&#x201D;`. For more on spans and fenced blocks, see the [code blocks guide](markdown-code-blocks.md).

A backslash is the other kind. The file `sq-escaped.md` holds `Jane typed \"Doe\" and Doe\'s.` and all four reader settings gave the same line:

~~~html
<p>Jane typed "Doe" and Doe's.</p>
~~~

The backslashes are gone and the quotes and the apostrophe stayed straight, with `smart` on or off. Per the CommonMark spec, a backslash has no escape effect inside a code span, so this route is for quotes in plain text.

## Curly quotes typed into the source

In this test, turning `smart` off didn't straighten curly quotes that were already in the file. An extra test file, `sq-extra-curly.md`, holds `Jane said`, then the word `Doe` between real curved double quotes, written with `printf` as UTF-8 bytes. Both `commonmark` and `markdown-smart` gave the same output:

~~~html
<p>Jane said &#x201C;Doe&#x201D;.</p>
~~~

## Checking a file for smart quotes

These steps use the test files from this post. Use your own file name in their place.

1. **Check the reader's default.** Run `pandoc --list-extensions=commonmark | grep smart`, or the same with `markdown`. A leading `-` means off by default and a `+` means on.
2. **Render with the setting you plan to use.** Run `pandoc -f commonmark+smart -t html --ascii sq-double.md`, or swap in `markdown-smart` or another setting from the table.
3. **Read the output for references.** Look for `&#x201C;`, `&#x201D;`, `&#x2018;`, `&#x2019;`, `&#x2013;`, `&#x2014;` or `&#x2026;` where you typed straight marks, hyphens or dots.
4. **Check the source bytes.** Count the lines that hold a non-ASCII byte with `grep -c '[^ -~]' sq-double.md`, run under the C locale (`LC_ALL=C`). It printed 0 for that file. For `sq-extra-curly.md`, which holds two curved quotes on one line, it printed 1, since `grep -c` counts lines with a match. The [invisible characters guide](markdown-invisible-characters.md) has more byte checks.
5. **Look at the bytes.** Run `od -c sq-extra-curly.md` to see where the multi-byte characters sit.
6. **Keep one mark straight.** Put a backslash just before it in plain text, or move it into a code span, then render again.

## Where Sashmark fits

In the Sashmark v1 plan, you would edit a Markdown file in place on its rendered page. The goal set for that is a clean Round-Trip, where every line you did not touch should keep the bytes it had before. The same v1 plan lists a Changes View to flag edits made to the file since your previous read, with no git needed. 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.

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