LegalDoc layout
This page documents the layout system used for legal-style documents in this repository.
It focuses on:
- what the layout supports right now
- how to use it in content
- what is coupled to Starlight
- what it would take to reuse in another Astro project
Scope and design intent
Section titled “Scope and design intent”The LegalDoc layout is intentionally scoped. It only activates when a page sets:
docLayout: legalDocThe scoped behavior is implemented as a combination of:
- content frontmatter (
docLayout) - a wrapper class on the rendered content panel (
content-panel--legal-doc) - legal-specific CSS in
legal-doc.scss - a legal-only remark transform that adds
legal-clauseclasses for paragraph numbering
This keeps the generic markdown/MDX attribute behavior separate from legal layout behavior.
What the layout supports
Section titled “What the layout supports”Current support is implemented in astro/src/styles/legal-doc.scss and astro/src/components/overrides/ContentPanel.astro.
1. Scoped activation by layout class
Section titled “1. Scoped activation by layout class”When the page has docLayout: legalDoc, the content panel receives:
content-panel--legal-doc
All legal CSS selectors are scoped to that class.
2. Section numbering for H2 headings
Section titled “2. Section numbering for H2 headings”Inside legal scope, each top-level h2 wrapper increments a section counter.
Rendered output pattern:
1 Tiltrædelsesdato og arbejdssted2 Ansvar og kompetencer3 Løn og lønforhandling
3. Automatic paragraph clause numbering
Section titled “3. Automatic paragraph clause numbering”Paragraphs marked with legal-clause are rendered with clause numbers using CSS counters:
1.1 ...1.2 ...2.1 ...
The legal-clause class is added by the legal-only remark plugin for ordinary paragraphs under h2 sections.
4. Opt-out from auto numbering
Section titled “4. Opt-out from auto numbering”Any paragraph with skip-number is excluded from auto-tagging and auto-number rendering.
5. Optional list-based legal numbering
Section titled “5. Optional list-based legal numbering”The stylesheet includes optional list styles for structured clauses:
ol.legal-clauses > lirenders assection.clause- nested
ol.legal-subclauses > lirenders assection.clause.subclause
This enables explicit legal list structures when paragraph auto-numbering is not enough.
6. Borderless legal table helper
Section titled “6. Borderless legal table helper”Within legal scope, elements using table-no-border remove table borders.
This is used for signature and party-information table layouts.
How to use it in this repository
Section titled “How to use it in this repository”Step 1: Set frontmatter on a page
Section titled “Step 1: Set frontmatter on a page”---title: Example Legal Documentdescription: ExampledocLayout: legalDoc---Step 2: Author headings and paragraphs normally
Section titled “Step 2: Author headings and paragraphs normally”Use ## headings for section boundaries and plain paragraphs for clauses.
The legal plugin + CSS counters do the numbering.
Step 3: Exclude specific paragraphs when needed
Section titled “Step 3: Exclude specific paragraphs when needed”Use a trailing remark-attr directive to apply skip-number:
Arbejdsstedet er ... <remark-attr class="skip-number" />You can combine attributes:
Arbejdsstedet er ... <remark-attr style="text-decoration: underline;" class="skip-number" />Step 4: Use optional list styles for explicit nested clauses
Section titled “Step 4: Use optional list styles for explicit nested clauses”<ol class="legal-clauses"> <li> First clause <ol class="legal-subclauses"> <li>First subclause</li> </ol> </li></ol>Step 5: Use borderless legal tables where needed
Section titled “Step 5: Use borderless legal tables where needed”<table class="table-no-border">...</table>Implementation map
Section titled “Implementation map”These files together define the LegalDoc layout behavior:
astro/src/content.config.ts- defines
docLayoutschema values (default,legalDoc)
- defines
astro/src/components/overrides/ContentPanel.astro- applies
content-panel--legal-doconly for legal pages
- applies
astro/src/styles/legal-doc.scss- contains all legal-scoped counters and helper styles
astro/src/config/remark-legal-clauses.mjs- auto-tags eligible paragraphs with
legal-clauseonly for legal pages
- auto-tags eligible paragraphs with
astro/astro.config.mjs- registers the legal remark plugin in markdown pipeline
Known constraints
Section titled “Known constraints”- Counter selectors currently target Starlight DOM wrappers (
.sl-markdown-content,.sl-heading-wrapper.level-h2). - Clause auto-tagging currently depends on
h2as the section boundary. - Paragraph auto-tagging is top-level and structure-sensitive by design.
- If content manually prefixes numbers (for example
**2.3**), those visual numbers can duplicate generated numbering.
Reuse in another Astro project
Section titled “Reuse in another Astro project”Reusing this in another Astro repo is practical, and there are three paths.
Path A: Astro + Starlight target (lowest friction)
Section titled “Path A: Astro + Starlight target (lowest friction)”- Copy
remark-legal-clauses.mjs. - Register it in
markdown.remarkPluginsafter the generic attr plugin. - Add
docLayoutto your content schema. - Add a content wrapper class toggle equivalent to
content-panel--legal-doc. - Copy legal CSS and keep selectors aligned with your rendered Starlight structure.
- Mark target pages with
docLayout: legalDoc.
Path B: Astro without Starlight (moderate adaptation)
Section titled “Path B: Astro without Starlight (moderate adaptation)”- Keep the same plugin strategy (
docLayout-gated legal clause tagging). - Keep the same scoped class strategy.
- Rewrite CSS selectors to your renderer DOM (heading wrappers and content container differ from Starlight).
- Verify counters with real rendered HTML before rollout.
Path C: Non-Astro markdown pipeline (highest adaptation)
Section titled “Path C: Non-Astro markdown pipeline (highest adaptation)”- Port legal clause tagging logic to your markdown AST toolchain.
- Recreate frontmatter gating in that toolchain.
- Reapply scoped CSS counters in the host renderer.
- Revisit syntax support for trailing directives if MDX/JSX parsing differs.
Minimal portability checklist
Section titled “Minimal portability checklist”- A frontmatter field to opt pages into legal layout.
- A scoped wrapper class that appears only for legal pages.
- A transform that adds
legal-clauseclasses only for opted-in pages. - CSS counters scoped to the wrapper class.
- Test fixtures with:
- multiple
h2sections - skip-number paragraphs
- structured clause lists
- borderless legal tables
- multiple
Relationship to remark-attr-for-mdx
Section titled “Relationship to remark-attr-for-mdx”remark-attr-for-mdxis generic and reusable across all documents.- LegalDoc layout is a separate, optional layer.
- Keeping them separate avoids layout coupling in the generic authoring plugin.