alto / commonmark
A collection of CommonMark extensions: code block titles, content slicing, heading level adjustment, file import/include, source display, table of contents, tabs, and link rewriting.
Fund package maintenance!
Requires
- php: ^8.3
- league/commonmark: ^2.7
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.92
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^12.5
Replaces
- alto/commonmark-code-block-title: dev-main
- alto/commonmark-content-slicer: dev-main
- alto/commonmark-heading-level: dev-main
- alto/commonmark-import: dev-main
- alto/commonmark-include: dev-main
- alto/commonmark-link-rewriter: dev-main
- alto/commonmark-source: dev-main
- alto/commonmark-table-of-contents: dev-main
- alto/commonmark-tabs: dev-main
This package is auto-updated.
Last update: 2026-04-17 00:18:49 UTC
README
Reusable league/commonmark extensions in a monorepo, installable as either the umbrella package alto/commonmark or as standalone per-extension packages.
Installation
composer require alto/commonmark
alto/commonmark declares replace on all standalone packages, so dependency resolution stays compatible whether you install one or all.
| Extension | Description | GitHub | Packagist |
|---|---|---|---|
| CodeBlockTitle | Titled fenced code blocks rendered as <figure> |
GitHub | Packagist |
| ContentSlicer | Wraps heading sections in semantic <section> elements |
GitHub | Packagist |
| HeadingLevel | Shift or remap heading levels across the document | GitHub | Packagist |
| Import | Import file contents into code blocks with line ranges | GitHub | Packagist |
| Include | Inline-include Markdown fragments for doc composition | GitHub | Packagist |
| LinkRewriter | Rewrite links & images via base URI, map, or regex | GitHub | Packagist |
| Source | Embed source files with line numbers and highlighting | GitHub | Packagist |
| TableOfContents | Auto-generated TOC from headings via @toc |
GitHub | Packagist |
| Tabs | Accessible ARIA tabbed UI from a simple @tabs directive |
GitHub | Packagist |
Extensions
CodeBlockTitle
The detail that signals craft — adds a title="..." to any fenced code block and wraps it in a semantic <figure>/<figcaption>. One small thing that makes a doc site feel finished.
```php title="hello.php" echo "Hello"; ```
<figure class="code-block has-title" data-title="hello.php"> <figcaption class="code-title">hello.php</figcaption> <pre><code class="language-php">echo "Hello"; </code></pre> </figure>
ContentSlicer
The rarest one in the set. Most processors stop at rendering headings as tags — this one restructures the entire document into a properly nested <section> tree, giving CSS selectors, JavaScript, and accessibility tooling something real to work with. No custom syntax needed.
## Subtopic 1 More content. ## Subtopic 2 Final content.
<section><h2>Subtopic 1</h2><p>More content.</p></section> <section><h2>Subtopic 2</h2><p>Final content.</p></section>
HeadingLevel
The one you don't need until you really do — then it's irreplaceable. Shifts, remaps, or transforms heading levels when embedding content from one context into another without heading hierarchy collisions.
# Title ## Section
<!-- with down: 1 --> <h2>Title</h2> <h3>Section</h3>
Import
Solves copy-paste drift between your docs and your source code. Pulls external file content directly into a code block — with line-range selection, language hinting, and depth-limited circular-import protection.
@import "src/Auth.php" {lines: 1-30, lang: php}
<pre><code class="language-php">// src/Auth.php lines 1–30 </code></pre>
Include
The backbone of large documentation sets. Pulls in and fully parses markdown fragments inline — making one-file-per-section composition possible without a build system.
@include "parts/intro.md"
<h2>Introduction</h2> <p>This is the introduction section.</p>
LinkRewriter
Indispensable plumbing for any hosted documentation setup. Decouples your markdown from your deployment URL with a composable chain of rewrite rules — base URI, exact maps, regex, and custom callbacks — applied in sequence.
[Guide](/getting-started) 
<!-- with base_uri: https://docs.example.com --> <a href="https://docs.example.com/getting-started">Guide</a> <img src="https://docs.example.com/assets/logo.svg" alt="Logo">
Source
The flagship of the set. Embeds a real file — not a copy — directly into your documentation, with syntax detection, line-range selection, line numbers, and per-line highlighting. Your docs stay in sync with your code by definition.
@source "src/Service.php" {lines: 9-11, numbers: true, highlight: "9,11"}
<div class="source-block"> <div class="source-path">src/Service.php</div> <pre><code class="language-php"><span class="line highlighted"><span class="line-number">9</span> public function add(int $a, int $b): int</span> <span class="line"><span class="line-number">10</span> {</span> <span class="line highlighted"><span class="line-number">11</span> return $a + $b;</span></code></pre> </div>
TableOfContents
A must-have for any document longer than a page. Drop @toc where you want the contents list — headings are collected, IDs assigned, and a navigable list rendered in one pass.
@toc {min: 2} ## Introduction ## Setup
<div class="table-of-contents" id="toc"> <ul> <li><a href="#introduction">Introduction</a></li> <li><a href="#setup">Setup</a></li> </ul> </div>
Tabs
One directive, fully accessible tabbed UI, zero JavaScript to write. Wraps content in proper ARIA tablist/tab/tabpanel roles with a self-contained switching script.
@tabs @tab "PHP" ```php echo 'Hello'; ``` @tab "JS" ```js console.log('Hello'); ``` @endtabs
<div class="tab-group" data-tabs-id="tabs-1"> <div class="tab-list" role="tablist"> <button class="tab active" role="tab" aria-selected="true" aria-controls="tabs-1-panel-0">PHP</button> <button class="tab" role="tab" aria-selected="false" aria-controls="tabs-1-panel-1">JS</button> </div> <div class="tab-panels"> <div class="tab-panel" id="tabs-1-panel-0" role="tabpanel">…</div> <div class="tab-panel" id="tabs-1-panel-1" role="tabpanel">…</div> </div> </div>
Support
If Alto CommonMark is useful to your project, sponsoring on GitHub is a great way to support continued development — and it's always appreciated.
License
MIT. See LICENSE.