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
Suggests
None
Provides
None
Conflicts
None
Replaces
- alto/commonmark-code-block-title: v1.0.0
- alto/commonmark-content-slicer: v1.0.0
- alto/commonmark-heading-level: v1.0.0
- alto/commonmark-import: v1.0.0
- alto/commonmark-include: v1.0.0
- alto/commonmark-link-rewriter: v1.0.0
- alto/commonmark-source: v1.0.0
- alto/commonmark-table-of-contents: v1.0.0
- alto/commonmark-tabs: v1.0.0
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.
Documentation
Read the complete guide at altophp.com/commonmark. It covers installation, extension selection, configuration, examples, and the security boundaries of file-reading extensions.
Packages
| 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>
Documentation · GitHub · Packagist
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>
Documentation · GitHub · Packagist
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>
Documentation · GitHub · Packagist
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>
Documentation · GitHub · Packagist
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>
Documentation · GitHub · Packagist
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">
Documentation · GitHub · Packagist
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>
Documentation · GitHub · Packagist
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>
Documentation · GitHub · Packagist
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>
Documentation · GitHub · Packagist
Contributing
Contributions of all kinds are welcome. Visit the project on GitHub to report a bug, suggest a feature, or open a pull request.
Before submitting code, run:
# Runs PHP CS Fixer, PHPStan, and PHPUnit
composer qa
Changes to public behavior should include tests and documentation.
Support
ALTO CommonMark is open source and independently maintained by Simon André. If it is useful to your work, you can support its continued development through GitHub Sponsors.
Sharing the package or starring it on GitHub also helps.
License
ALTO CommonMark is released by ALTO PHP under the MIT License.