Skip to content

Headings

Headings are your document's scaffold: Markdown # marks become \section, \subsection, and friends. TeXSmith retunes them using template settings, document base levels, and promotion rules so the hierarchy stays sane even when the source is messy.

Markdown is loose: some files start at ##, others at ###, and multi-file builds mix it all. TeXSmith computes offsets per fragment to line things up: find the shallowest heading, derive an offset, then add the template base level. This page walks that math, how title promotion changes it, and how slots keep fragments independent.

How offsets are computed

  1. Drop any sections routed to slots (e.g. abstract) before aligning the remaining content for that slot.
  2. If promotion is on and the first heading is uniquely the highest, it becomes metadata and is ignored for offsets.
  3. Look at the shallowest heading that remains:
  4. <h1> → offset 0
  5. <h2> → offset -1
  6. <h3> → offset -2
  7. No headings → offset 0
  8. The effective base level for a fragment is:
template slot base + document base_level + fragment offset
  1. The rendered level is html_level + effective_base - 1.

Offsets are per fragment: each slot fragment gets its own pass, so moving a heading into an abstract slot cannot force the main matter down a level.

Template and document base levels

Classic classes anchor headings differently: article tops out at \section, while memoir can start at \chapter or \part. Templates encode that base level per slot: abstract as a section, main matter as a chapter, etc. Adjust it per document via front matter or CLI; the template default is used if you set nothing.

press:
  template: book
  base_level: chapter # To not use parts by default
texsmith doc.md --template book --base-level chapter

Promotion rules

Promotion lifts the first heading into the document title. Because that heading leaves the body, the next shallowest heading drives the offset. Promotion is on by default: if there is no metadata title and the first heading is uniquely the shallowest, it is promoted and skipped in the offset math.

A declared title in front matter disables promotion. So do --no-promote-title on the CLI and TitleStrategy.NONE in the Python API.

--strip-heading / TitleStrategy.DROP removes the first heading without promoting it.

Want an explicit title plus promotion? Declare title, keep promotion on, and the declared title wins while headings are still measured against the remaining body.

Worked examples

All examples use the article template (base_level=section):

  • Metadata title present; headings start at ##: fragment offset -1 + template base 1 → first heading renders as \section, nested ### as \subsection.
  • No metadata title; first heading is # Title: it is promoted and ignored for offsets, so the remaining ## headings still become \section.
  • Headings begin at ## with no # anywhere: offset -1 again, so the highest heading still aligns to \section.
  • Slot extraction: if # Abstract is routed to the abstract slot and stripped there, the remaining main-matter fragment starts at ## and is aligned to \section (the removed # does not push sections down to subsections).

Multidocument behavior

When rendering multiple documents, each document (and each of its slot fragments) computes its own offset independently. A root title in a multi-file build does not block promotion in subdocuments, and each slot still adds the template base level before applying the fragment offset.

Quick reference

  • Offsets are 1 - shallowest_heading_level after promotion/slot stripping.
  • Effective base = template slot base + document base_level + fragment offset.
  • Promotion is default; disable with --no-promote-title or a declared title.
  • Slots are aligned independently; moving a heading to a slot never changes the offset of the remaining content.