Skip to content

Add option to disable section wrapping in HTML output - #266

Merged
dereuromark merged 1 commit into
masterfrom
feature/optional-section-wrapping
Aug 1, 2026
Merged

Add option to disable section wrapping in HTML output#266
dereuromark merged 1 commit into
masterfrom
feature/optional-section-wrapping

Conversation

@dereuromark

@dereuromark dereuromark commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Document-level headings are wrapped in <section> elements by default, with the heading id hoisted onto the wrapper. There was no way to turn this off short of post-processing the HTML.

That is a real migration blocker: stylesheets written against a flat Markdown heading structure break silently. The motivating case is sibling selectors such as .stack > * + *, which stop matching once every heading and its content sit in their own wrapper. Raised in markup-carve/carve#427 and before in jgm/djot#221 .

What this adds

An opt-out. The default is unchanged.

$converter = new DjotConverter(sections: false);
// or
$converter->getHtmlRenderer()->setSections(false);
djot convert doc.djot --no-sections
{#install .featured}
## Setup
output
default <section id="install"> / <h2 class="featured">Setup</h2>
sections: false <h2 id="install" class="featured">Setup</h2>

Why it is small

renderHeading() already emits exactly this shape. It is the path used today for headings nested inside divs and blockquotes. Disabling section wrapping routes document-level headings through that same path, so the behavior is one that already existed and was already covered, just not reachable at document level.

Two things worth calling out:

  • No id loss. The explicit id reservation pass still runs first, so generated ids and their dedup suffixes are byte-identical in both modes. This is not true of the equivalent workaround in djot.js, where the id is moved onto the section during parsing, so unwrapping the section with a filter silently drops every anchor including hand-written ones. Because djot-php decides placement at render time, there is nothing to recover.
  • Scope. Section wrapping is an HTML concern. The footnote endnotes section, the round-trip abbreviation metadata, and the plain text, Markdown and ANSI renderers are all unaffected.

Docs

Added to docs/guide/parser-options.md, docs/guide/converters.md, docs/reference/api.md, docs/reference/cli.md, and a migration note in docs/cookbook/markdown.md, which is where someone hitting this problem is most likely to look.

Document-level headings are wrapped in section elements by default, with the
heading id hoisted onto the wrapper. Stylesheets that assume a flat heading
structure, such as sibling selectors like `.stack > * + *`, break when
migrating from Markdown, and there was no way to opt out short of
post-processing the HTML.

Add `HtmlRenderer::setSections(false)`, a `sections` constructor option on
DjotConverter, and a `--no-sections` CLI flag. The default is unchanged.

With sections disabled, document-level headings render through the existing
`renderHeading()` path already used for headings nested inside divs and
blockquotes, so they keep their id inline and no attributes are dropped. The
explicit id reservation pass still runs first, so generated ids and their
dedup suffixes are identical in both modes.

Section wrapping is an HTML concern only. The footnote endnotes section, the
round-trip abbreviation metadata, and the plain text, Markdown and ANSI
renderers are all unaffected.
@dereuromark dereuromark added the enhancement New feature or request label Aug 1, 2026
@codecov

codecov Bot commented Aug 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.40%. Comparing base (5c29c6e) to head (7ebab1e).

Additional details and impacted files
@@             Coverage Diff              @@
##             master     #266      +/-   ##
============================================
+ Coverage     92.39%   92.40%   +0.01%     
- Complexity     3668     3673       +5     
============================================
  Files           109      109              
  Lines         10407    10421      +14     
============================================
+ Hits           9616     9630      +14     
  Misses          791      791              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@dereuromark
dereuromark merged commit 20073dc into master Aug 1, 2026
6 checks passed
@dereuromark
dereuromark deleted the feature/optional-section-wrapping branch August 1, 2026 13:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant