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
ifdefkeeps its content when a symbol is defined.ifndefkeeps 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.