PHPackages                             ekumanov/flarum-ext-markdown-tables - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Parsing &amp; Serialization](/categories/parsing)
4. /
5. ekumanov/flarum-ext-markdown-tables

ActiveFlarum-extension[Parsing &amp; Serialization](/categories/parsing)

ekumanov/flarum-ext-markdown-tables
===================================

Markdown tables for Flarum 2.0, with Tiptap rich-text editor integration.

v1.0.2(1mo ago)0186↓50%MITJavaScriptPHP ^8.2

Since Apr 30Pushed 1mo agoCompare

[ Source](https://github.com/ekumanov/flarum-ext-markdown-tables)[ Packagist](https://packagist.org/packages/ekumanov/flarum-ext-markdown-tables)[ RSS](/packages/ekumanov-flarum-ext-markdown-tables/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (1)Dependencies (1)Versions (4)Used By (0)

Markdown Tables for Flarum 2.0
==============================

[](#markdown-tables-for-flarum-20)

[![License](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)](LICENSE)[![Latest Stable Version](https://camo.githubusercontent.com/9e687c5d6f44e8812c2f8b55db3db3a0bcbfa6180cb79a62680bfb95440120f1/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f656b756d616e6f762f666c6172756d2d6578742d6d61726b646f776e2d7461626c65732e737667)](https://packagist.org/packages/ekumanov/flarum-ext-markdown-tables)[![Total Downloads](https://camo.githubusercontent.com/afa35ec1b1ec36edd2e1c944dd2f463c2db1a28346af97d2105b60d177e605bb/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f656b756d616e6f762f666c6172756d2d6578742d6d61726b646f776e2d7461626c65732e737667)](https://packagist.org/packages/ekumanov/flarum-ext-markdown-tables)[![Backend Tests](https://github.com/ekumanov/flarum-ext-markdown-tables/actions/workflows/backend.yml/badge.svg)](https://github.com/ekumanov/flarum-ext-markdown-tables/actions/workflows/backend.yml)

Adds proper markdown table support to Flarum 2.0, both in rendered posts and inside the [FriendsOfFlarum Rich Text](https://discuss.flarum.org/d/38789-friendsofflarum-rich-text-wysiwyg) WYSIWYG editor.

This is a Flarum 2.0 port of [askvortsov/flarum-markdown-tables](https://github.com/askvortsov1/flarum-markdown-tables) — the original Flarum 1.x extension was built on `askvortsov-rich-text` (ProseMirror-based), which has been replaced in 2.0 by `fof-rich-text` (Tiptap v3-based). The port was made with [Claude Code](https://claude.com/claude-code).

Screenshots
-----------

[](#screenshots)

LightDark[![Light mode](screenshots/light-desktop.png)](screenshots/light-desktop.png)[![Dark mode](screenshots/dark-desktop.png)](screenshots/dark-desktop.png)Tables size to their natural content, so a typical post table fits comfortably on mobile. Tables wider than the post column get a horizontal-scroll wrapper instead of forcing every cell to crush.

What you get
------------

[](#what-you-get)

Type a standard pipe table in the composer:

```
| Name  | Role   | Notes           |
|-------|:------:|----------------:|
| Alice | Admin  | Founding member |
| Bob   | Editor | Joined 2024     |
| Carol | Reader | Lurker mode     |

```

…and your post renders it as a proper, styled HTML table — with header row, column alignment from the `:---:` markers, alternating row backgrounds, and horizontal scrolling when the table is wider than the post column.

Features
--------

[](#features)

- **Pipe-table parsing** — standard GitHub-flavoured Markdown syntax. Handles left/center/right column alignment via `:---`, `:---:`, and `---:` separators.
- **Rich-text editor integration** — when [`fof/rich-text`](https://github.com/FriendsOfFlarum/rich-text) is enabled, an "Insert table" button appears in the composer toolbar. Set columns and rows, click insert, type into cells.
- **Markdown round-trip** — tables created in the WYSIWYG editor serialize back to clean pipe-table markdown, so the post stays human-readable in the database and editable in plain mode.
- **Responsive overflow** — wide tables get wrapped in a horizontally-scrolling container so they never blow out narrow viewports.
- **Theme-aware** — borders, header background, and zebra striping use Flarum's CSS custom properties, so tables follow your light/dark scheme automatically.
- **No configuration** — install, enable, done.
- **Works without `fof/rich-text`** too — if you don't use the WYSIWYG editor, posts still parse and render markdown tables correctly.

Requirements
------------

[](#requirements)

- **Flarum 2.0** (tested against 2.0.0-rc.1)
- **PHP 8.2+**
- Optional: **`fof/rich-text` 2.0+** for the WYSIWYG insert button. Markdown rendering works without it.

Installation
------------

[](#installation)

```
composer require ekumanov/flarum-ext-markdown-tables
rm -rf storage/formatter/*
php flarum cache:clear
```

Then enable the extension in the admin panel under **Extensions &gt; Markdown Tables**.

> **Why `rm -rf storage/formatter/*`?** Flarum compiles the s9e/text-formatter renderer into a PHP class under `storage/formatter/Renderer_*.php`. `php flarum cache:clear` does **not** touch that file. If a renderer was compiled before this extension was active, it has no template branches for `` / `` / `` etc., and existing posts that contain table XML will silently render as empty space. Removing the file forces a regenerate that includes the table templates.

Upgrading from Flarum 1.x with `askvortsov/flarum-markdown-tables`
------------------------------------------------------------------

[](#upgrading-from-flarum-1x-with-askvortsovflarum-markdown-tables)

If you're coming from Flarum 1.x and previously had [`askvortsov/flarum-markdown-tables`](https://github.com/askvortsov1/flarum-markdown-tables) installed, your existing post XML is already compatible — both extensions enable the same s9e/text-formatter `PipeTables` plugin and the stored XML uses the same `` tag names. **No re-parse of old posts is needed.**

But you almost certainly **do** need to clear the formatter cache, because during the period between the 1.x→2.0 migration and the install of this extension the renderer was recompiled without table templates. Run:

```
composer require ekumanov/flarum-ext-markdown-tables
rm -rf storage/formatter/*
php flarum cache:clear
php flarum assets:publish
```

After that, every existing post that already had a markdown table will render as a real `` again — no edits required.

Updating
--------

[](#updating)

```
composer update ekumanov/flarum-ext-markdown-tables
php flarum cache:clear
```

How it works
------------

[](#how-it-works)

### Backend

[](#backend)

The PHP side is small. We register an `Extend\Formatter` callback that enables the s9e/text-formatter [PipeTables](https://s9etextformatter.readthedocs.io/Plugins/PipeTables/) plugin:

```
(new Extend\Formatter())
    ->configure(function (Configurator $config) {
        $config->PipeTables;
    });
```

PipeTables is already shipped inside `s9e/text-formatter` (a Flarum core dependency), so this adds zero new code paths to the parser — it just turns on a feature that's already there.

### Frontend (forum, always-on)

[](#frontend-forum-always-on)

Two small things happen on the forum side regardless of which editor you use:

1. **Wrap rendered tables for horizontal scroll.** PipeTables emits bare `` elements; without a wrapper, a table wider than the post column overflows or breaks layout. We hook into `Post#oncreate`/`onupdate` and wrap each `` in a `` with `overflow-x: auto`. The wrap is idempotent — a `data-markdown-tables-wrapped` attribute prevents double-wrapping when Mithril rerenders.
2. **Style the table.** Borders use `var(--control-bg)`, header rows pick up `var(--control-bg)` as background, even rows get a subtle striping. Everything goes through Flarum 2's CSS custom properties so it follows the theme automatically.

### Frontend (composer, when `fof/rich-text` is enabled)

[](#frontend-composer-when-fofrich-text-is-enabled)

This is where most of the code lives, because Tiptap doesn't know about pipe tables out of the box. The integration happens in four pieces:

#### 1. Tiptap node specs

[](#1-tiptap-node-specs)

`fof/rich-text` exposes `Node` from `@tiptap/core` via `flarum.reg.get('fof-rich-text', 'common/tiptap/tiptap')`. We use that to define six nodes:

```
table > tableHead > tableRow > tableHeader   (one head row)
      > tableBody > tableRow > tableCell     (zero or more body rows)

```

Each node has standard `parseHTML` / `renderHTML` rules. Cell nodes carry an optional `style` attribute that holds the alignment (`text-align: left|center|right`), parsed from the markdown separator and replayed when the cell renders.

The `Node` constructor is captured lazily, after `fof/rich-text`'s async chunk loads — resolving it at module load time would crash, because the chunk hasn't loaded yet. We push our setup work onto `TextEditor.prototype.oninit`'s `_loaders` array, which Tiptap's editor awaits before construction.

#### 2. Markdown parser tokens

[](#2-markdown-parser-tokens)

`fof/rich-text`'s `MarkdownParserBuilder` uses `markdown-it` in CommonMark mode, which has the `table` rule disabled. We patch its prototype to:

- Call `.enable('table')` on the tokenizer.
- Add token-to-node mappings for `table`, `thead`, `tbody`, `tr`, `th`, `td`. The `th`/`td` mappings lift the `style` attribute from the markdown-it token onto the node attributes — that's how alignment survives parsing.

#### 3. Markdown serializer

[](#3-markdown-serializer)

When the user types a table in the WYSIWYG editor and hits submit, Tiptap calls our serializer to turn the doc back into markdown. We hook `MarkdownSerializerBuilder.prototype.buildNodes` and add a `table` handler that walks `tableHead` → `tableRow` → `tableHeader`, emits the header pipe row, then the alignment separator row (`| --- | :---: | ---: |`), then each `tableBody` row.

Pipe characters that appear inside a cell are escaped to `\|` so they don't break the table syntax.

#### 4. Toolbar dropdown

[](#4-toolbar-dropdown)

`InsertTableDropdown.js` is a Mithril component that extends Flarum's `Dropdown`. Its menu has two faces:

- **Outside a table** — a small form with "columns" and "rows (including header)" inputs and an "Insert table" button. Clicking it dispatches our `insertTable(rows, cols)` Tiptap command, which builds a fresh `table` node populated with single-space cells (PipeTables drops empty cells, so the space keeps the structure intact through round-trips).
- **Inside a table** — a context menu with "Insert/delete row before/after", "Insert/delete column before/after", and "Delete table".

The button is added to the toolbar via `extend(TiptapMenu.prototype, 'items', …)`, so it sits alongside Bold, Italic, Image, etc.

### A note on bundle isolation

[](#a-note-on-bundle-isolation)

Our extension does *not* bundle `@tiptap/extension-table`. Instead we built minimal Node specs ourselves and reused `fof/rich-text`'s exposed `@tiptap/core` Node constructor. This avoids shipping a duplicate copy of Tiptap-core or `prosemirror-tables` — nodes share the same Tiptap instance the editor is using, so `instanceof` checks and schema lookups all line up.

The trade-off: we don't get column-resize handles or the cell-selection plugin you'd get from `@tiptap/extension-table`. For a markdown forum, that's the right trade — pipe tables can't express column widths anyway, so column-resize would only set state that disappears on save.

Limitations
-----------

[](#limitations)

- **Single-column tables don't render.** This is a PipeTables limitation, not ours — GitHub-flavoured Markdown's pipe-table grammar requires at least two columns.
- **Cells contain inline content only.** No nested block elements (lists, quotes, code blocks) inside cells. This matches the standard pipe-table specification.

Links
-----

[](#links)

- [Packagist](https://packagist.org/packages/ekumanov/flarum-ext-markdown-tables)
- [GitHub](https://github.com/ekumanov/flarum-ext-markdown-tables)
- [Original Flarum 1.x extension](https://github.com/askvortsov1/flarum-markdown-tables) by Alexander Skvortsov

License
-------

[](#license)

MIT — see [LICENSE](LICENSE). Original copyright notice retained for the Flarum 1.x extension this is ported from.

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance92

Actively maintained with recent releases

Popularity16

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity48

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

3

Last Release

40d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/a23c4539c1c2283960743eb8b92e2c56fb2c5f33a7b44bd03a3d07b882fd67ed?d=identicon)[ekumanov](/maintainers/ekumanov)

---

Top Contributors

[![ekumanov](https://avatars.githubusercontent.com/u/24654623?v=4)](https://github.com/ekumanov "ekumanov (8 commits)")

---

Tags

tiptapmarkdownextensiontablesflarum

### Embed Badge

![Health badge](/badges/ekumanov-flarum-ext-markdown-tables/health.svg)

```
[![Health](https://phpackages.com/badges/ekumanov-flarum-ext-markdown-tables/health.svg)](https://phpackages.com/packages/ekumanov-flarum-ext-markdown-tables)
```

###  Alternatives

[flarum-lang/russian

Russian language pack for Flarum.

12127.5k](/packages/flarum-lang-russian)[flarum-lang/french

French language pack to localize the Flarum forum software plus its official and third-party extensions.

1936.5k](/packages/flarum-lang-french)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
