Skip to content

Conditional content

Gate parts of a manuscript so they appear only in certain builds — a private print that carries dedications the public edition omits, or a passage meant only for the PDF. One source, many editions, no edits between builds.

The two primitives

  • ifdef keeps its content when a symbol is defined.
  • ifndef keeps its content when a symbol is not defined.

Both work as blocks and as inline spans, and both take a required symbol:

::: {.ifdef symbol="personal"}
A dedication only the private edition should carry.
:::

Thanks for reading[ this public edition]{.ifndef symbol="personal"}.

An undefined symbol is simply false. Multiple symbols are OR-combined (symbol="a b" matches when either is defined); nest two ifdefs for "and". A bare ifdef with no symbol is an error.

Symbols are build configuration

Which symbols are defined describes how you're building, not anything about the manuscript — so symbols live in project.conf, never in pandoc.yaml. You never edit your source to produce a different edition; you select a configuration at publish time.

A configuration is a named set of symbols:

# project.conf
KEYSTONE_DEFINE_private="personal annotations drafts"

The name (private) is the edition label; the value lists the symbols your content is tagged with. Select it when publishing:

make publish using=private
make publish format=epub using=private

With no selection (the KEYSTONE_USING default empty and no using=), nothing is defined — you get the plain public edition.

The configuration name is appended to the artifact filename, so editions never overwrite each other:

artifacts/mybook-book-20260101.pdf            # plain build
artifacts/mybook-book-private-20260101.pdf    # using=private

Selecting a name you never declared is a hard error; individual symbols are free-form (an undefined one just gates to nothing). When a configuration is active the build prints the defined set so you can confirm it.

Targeting a format

Every build automatically defines a symbol for its output format — latex for PDF, plus epub, docx, odt. You can gate on these directly, but the convenience shortcuts read better:

::: latex-only
\begin{center}Raw LaTeX, included only in the PDF.\end{center}
:::

::: epub-only
A note that only makes sense in the e-book.
:::

latex-only, epub-only, docx-only, and odt-only are thin wrappers over ifdef. These format names are reserved — a configuration can't redefine them.

Cleaner authoring with shortcuts

Repeating symbol="personal" everywhere is noisy. Define a shortcut once that supplies the symbol as a default:

personal:
  class: ifdef
  interface:
    symbol:
      bind: class.symbol
      default: personal

Now the manuscript reads cleanly, as a block or inline:

::: personal
A private dedication.
:::

For you[, and only you]{.personal}.

See Writing your own shortcuts.

EPUB font embedding and excluded content

EPUB embeds the fonts your manuscript references, and that set is collected before conditional gating is applied. A font used only inside excluded content is still embedded — it affects the archive's size, never what a reader sees.