Skip to content

Ferromark Flavored Markdown

Ferromark Flavored Markdown (FFM)

FFM is the name for Ferromark's opt-in authoring syntax on top of CommonMark and GFM. It groups features for publishing richer documents without requiring a new file format. Turn them all on with the ffm preset, or enable each feature separately. Caption, attribution, table layout, marked text, inserted text, inline notes, bracketed spans, guillemet digraphs, and technical abbreviations are off in Node.js defaults and in every Rust preset except ffm(). Other features have their own defaults. Keep unused syntax disabled to avoid its parsing cost.

For standard Markdown, start with CommonMark and GFM. For option defaults and HTML trust, see Node.js, Rust, and rendering and trust.

Figures and sources

![Three components connected by arrows](pipeline.svg "Browser title"){.diagram}

: The **processing pipeline** {#pipeline .figure-wide}

> A memorable passage.
: Jane Doe, **author** {#source .byline}

imageCaptions / image_captions gives a standalone image a visible <figcaption>; its alternative text stays on <img>. imageAttributes / image_attributes adds image classes and IDs. blockquoteAttributions / blockquote_attributions puts a source line outside the quote in a figure caption. IDs and classes on the caption line attach to the figure. Both caption forms accept inline Markdown and can follow their block immediately or after one blank line. See image boundaries and quote boundaries.

Tables with captions and spans

| Item | Net | Tax |
| :--- | ---: | ---: |
| Book | 20.00 | 1.40 |
| Gift | Included ||

: Prices *today* {#prices .price-list}

mergedTableCells / merged_table_cells reads adjacent closing pipes as a horizontal span. tableAttributes / table_attributes adds a caption and optional ID/classes to a GFM table. Renderer options tableColgroup and tableColumnNames (Rust: table_colgroup, table_column_names) emit CSS hooks for columns. Set column widths in CSS. See the table syntax and CSS example.

Inline meaning and attributes

This is ==important==.^[An explanatory note.]
We ++added this sentence++ in the second edition.

The French [C’est la vie]{lang=fr} fits here.
[Documentation](https://example.org){.external hreflang=en}

highlight renders ==...== as <mark>; inlineFootnotes / inline_footnotes turns ^[...] into a footnote, and insertions renders ++...++ as semantic <ins> markup. These options are independent of code highlighting, strikethrough, and reference footnotes. bracketedSpans / bracketed_spans enables [text]{...}. extendedAttributes / extended_attributes enables key/value attributes on spans, links, headings, tables, images, and figures. Basic ID/class suffixes also have their own feature options. Read the writing syntax and attribute mapping rules, especially before embedding untrusted output in a host framework that uses data-* attributes.

More authoring syntax

UseExampleNode.js optionRust option
Reference notesA fact.[^source]footnotesfootnotes
Definition listsTerm followed by : ExplanationdefinitionListsdefinition_lists
Heading IDs/classes# Title {#title .section}headingAttributesheading_attributes
Math notation$x^2$mathmath
Superscript/subscriptx^2^, H~2~Osuperscript, subscriptsuperscript, subscript
Source metadataLeading --- or +++ blockfrontMatterfront_matter
Source comments// note at line startlineCommentsline_comments
Alert boxes> [!NOTE]calloutsHtmlRendererOptions::callouts

These options have separate boundaries. Math needs downstream typesetting. Front matter exposes raw metadata text, without parsing YAML or TOML values. Subscript takes precedence over single-tilde strikethrough when enabled. Callouts are a renderer feature, enabled in Node.js and the default Rust renderer; strict Rust specification profiles disable them. Other defaults are listed in the configuration guides. See front matter, line comments, and the feature comparison for further details.

Use the preset

import { toHtml } from "ferromark";

const html = toHtml("![Logo](logo.svg)\n\n: Company logo", { preset: "ffm" });

preset: "ffm" starts from GFM plus every syntax on this page except subscript, math, front matter, and MDX, which change the meaning of GFM input or need downstream processing. In Node.js it also enables technical abbreviation markup. Individual options still override the preset, and the output policy (renderPolicy, table colgroups, typography) stays your choice.

The preset trades speed for convenience. On documents that use none of its syntax, parsing takes 10–55% longer than with GFM alone, mostly for definition lists; abbreviation markup adds render time in proportion to the prose. Enable individual features when a document needs only a few. The preset decision lists the measured cost of each option.

In Rust, ParserOptions::ffm() selects the same syntax. Pair it with HtmlRendererOptions::gfm() and, for abbreviations, HtmlRenderer::with_abbreviations(AbbreviationOptions::default()). Guillemet digraphs only become quotes when a typography pass with a language runs.

Enable a small dialect

import { toHtml } from "ferromark";

const html = toHtml("![Logo](logo.svg)\n\n: Company logo", {
  imageCaptions: true,
});

The same option can be set as image_captions: true in Rust ParserOptions. Other features remain at their defaults. Each additional enabled syntax may add work even when a document does not use it; the runtime profiles and linked feature reports provide measurements.

Language-aware quotes

Il a dit <<Bonjour>> avant de partir.

guillemetDigraphs / guillemet_digraphs keeps doubled angle brackets as text instead of reading them as raw HTML or autolinks. A typography pass with an explicit language then turns balanced pairs into that language's primary quotation marks, for example « Bonjour » in French or „Bonjour“ in German. Unbalanced, escaped, and protected markers, URLs, and shift expressions stay literal. For portable input, write straight quotes and select a typography language instead. See the typography guide.

Technical abbreviations

The API returns JSON over HTTP.

Technical abbreviation markup adds no Markdown syntax. Set autoAbbreviations in Node.js, or use HtmlRenderer::with_abbreviations in Rust, to wrap complete uppercase technical terms in semantic <abbr> markup. A small built-in dictionary supplies common titles; unknown candidates receive a bare wrapper. The abbreviations map (Rust: AbbreviationOptions::overrides) adds a mixed-case term, changes a title, or suppresses a false positive with null (Rust: None). Matching runs during rendering, so the parsed AST and heading metadata stay unchanged. Code, math, raw HTML, MDX attributes, URLs, link destinations, and image alternative text are never wrapped. See the API, token boundaries, and known limitations.

Typography transforms punctuation after parsing, and MDX captures component syntax for downstream integration. Their processing and trust boundaries differ from FFM's authoring syntax.