Skip to content

erikvullings/slimdown-js

Repository files navigation

slimdown-js

npm Bundle size

A basic regex-based Markdown parser based on the gist by Johnny Broadway, converted from PHP to TypeScript, extended with several additional elements (images, tables, code blocks, underscores) and published to npm.

Inspired by:

Supports the following elements (and can be extended via addRule(regexp: RegExp, replacement: string | Function)):

  • Headers: # Header 1, or ## Header 2
  • Images: ![ALT TEXT](https://my_image_source)
  • Links: [ALT TEXT](https://my_image_source)
  • Bold: **bold** or __bold__
  • Emphasis: *italics* or _italics_
  • Deletions: ~~bold~~
  • Quotes: This is a quote: :"my quote":
  • Inline code: This is \inline` code`.
  • Code blocks: Use three subsequent backticks ` to open and close a code block.
  • Block quotes: Lines starting with > <QUOTED_TEXT>.
  • Tables: Use pipes | to separate columns, and '-' to separate the table header from its body.
  • Table captions: [Caption Text] before a table
  • Table column spanning: Use || followed by empty cells to span columns
  • Math expressions: Inline $E = mc^2$ and block $$\int_0^1 x dx$$
  • Task lists: - [x] Completed or - [ ] Todo
  • Definition lists: Term : Definition (capitalized terms and definitions)
  • Underscores (Escape underscores to keep them \_)
  • Ordered/unordered lists (up to three levels deep, may be nested)
  • Superscript and subscript (z~1~ or a^2^)
  • Footnotes, e.g. footnote[^1] and [^1]: Footnote reference.
  • Hard line breaks: two or more trailing spaces followed by a newline produce a <br>.
  • Autolinks: <https://example.com> renders as a clickable link.
  • Fenced code blocks with language hint: ```js emits <code class="language-js"> for syntax highlighters.

Size

The main reason for using this library, which hasn't been extensively tested and is not completely compatible with the spec, is to have something small. Version 1.0.0 with Phase 1 enhancements is approximately 2.8 kB compressed.

For more advanced scenario's, however, I can recommend marked, albeit at a bigger size: marked.min.js is 23.372 bytes uncompressed, and 7.684 bytes using gzip.

Installation

npm install slimdown-js

Quick Start

CommonJS (Node.js)

const { render } = require('slimdown-js');

const html = render('# Hello World\n\nThis is **bold** text with $math$!');
console.log(html);

ES Modules

import { render } from 'slimdown-js';

const html = render('# Hello World\n\nThis is **bold** text with $math$!');
console.log(html);

TypeScript

import { render, addRule, RegexReplacer } from 'slimdown-js';

const html: string = render('# TypeScript Example');

Browser (CDN)

See the example here

UMD via unpkg:

<script src="https://unpkg.com/slimdown-js/dist/slimdown.umd.js"></script>
<script>
  const html = window.slimdownJs.render('# Browser Example');
</script>

UMD via jsDelivr:

<script src="https://cdn.jsdelivr.net/npm/slimdown-js/dist/slimdown.umd.js"></script>
<script>
  const html = window.slimdownJs.render('# Browser Example');
</script>

Native ESM (no bundler needed):

<script type="module">
  import { render } from 'https://esm.sh/slimdown-js';
  document.body.innerHTML = render('# Hello from ESM!');
</script>

For more examples, see examples.md.

Playground

Head over to flems.io for a live example.

API Reference

render(markdown, options?)

Parameter Type Default Description
markdown string The Markdown text to render
options.removeParagraphs boolean false Strip the <p> wrapper from top-level paragraphs
options.externalLinks boolean false Add target="_blank" to all links

The legacy positional form render(markdown, removeParagraphs?, externalLinks?) is also supported for backwards compatibility.

addRule(regex, replacement)

Adds a custom parsing rule. Rules are applied during the pre-paragraph phase.

import { addRule } from 'slimdown-js';

// Convert :) to a smiley
addRule(/(\W)\:\)(\W)/g, '$1<img src="smiley.png" alt=":)" />$2');

Development

Use npm test to run the test suite and npm run test:watch for continuous testing. Uses tsup to compile to CommonJS, ESM, and UMD output formats.

Usage

Here is the general use case:

import { render } from 'slimdown-js';

console.log(
  render('# Page title\n\nAnd **now** for something _completely_ different.',),
);

Adding rules

A simple rule to convert :) to an image:

import { render, addRule } from 'slimdown-js';

addRule ('/(\W)\:\)(\W)/', '$1<img src="smiley.png" />$2');

console.log(render(('Know what I\'m sayin? :)'));

In this example, we add GitHub-style internal linking (e.g., [[Another Page]]).

import { render, addRule } from 'slimdown-js';

const mywiki_internal_link = (title: string) =>
  `<a href="${title.replace(/[^a-zA-Z0-9_-]+/g, '_')}">${title}</a>`;

addRule('/[[(.*?)]]/e', mywiki_internal_link('$1'));

console.log(render('Check [[This Page]] out!'));

A longer example

import { render } from 'slimdown-js';

console.log(render(`# A longer example

And *now* [a link](http://www.google.com) to **follow** and [another](http://yahoo.com/).

* One
* Two
* Three

## Subhead

One **two** three **four** five.

One __two__ three _four_ five __six__ seven _eight_.

1. One
2. Two
3. Three

More text with `inline($code)` sample.

> A block quote
> across two lines.

More text...`));

Math Support

import { render } from 'slimdown-js';

// Inline math
console.log(render('Einstein discovered $E = mc^2$ in 1905.'));
// Output: <p>Einstein discovered <span class="math-inline">E = mc^2</span> in 1905.</p>

// Block math
console.log(render(`The Gaussian integral:

$$
\\int_{-\\infty}^{\\infty} e^{-x^2} dx = \\sqrt{\\pi}
$$

is fundamental in mathematics.`));

Task Lists

import { render } from 'slimdown-js';

console.log(render(`- [x] Learn markdown
- [ ] Practice LaTeX
- [X] Write documentation`));
// Output: <ul>
//   <li><input type="checkbox" checked disabled> Learn markdown</li>
//   <li><input type="checkbox" disabled> Practice LaTeX</li>
//   <li><input type="checkbox" checked disabled> Write documentation</li>
// </ul>

Enhanced Tables

import { render } from 'slimdown-js';

// Table with caption and column spanning
console.log(render(`[Sales Data 2024]
| Product | Q1 Sales |       |      | Q2 |
| ------- | -------- | ----- |
| Widget  | $1000    | $1200 |
| Gadget  | $800     | $900  |
`));
// Creates table with caption and Q1 Sales spanning multiple columns

Definition Lists

import { render } from 'slimdown-js';

console.log(render(`Technology : Computer and software tools
Science : Study of the natural world`));
// Output: 
// <dl><dt>Technology</dt><dd>Computer and software tools</dd></dl>
// <dl><dt>Science</dt><dd>Study of the natural world</dd></dl>

About

A regex-based Markdown parser

Resources

License

Stars

Watchers

Forks

Packages