jp-markdown
v1.3.3
Published
Markdown-to-HTML parser with syntax-highlighted code blocks, line numbers, copy buttons, and Tailwind-friendly element styling.
Maintainers
Readme
JP-MarkDown
A customizable Markdown → HTML parser for Node.js. Built on marked and highlight.js, with first-class support for styled code blocks, Tailwind-friendly element classes, and optional full-document export.
Perfect for docs sites, admin previews, and anywhere you need server-rendered markdown with polished output.
Install
npm install jp-markdownQuick start
const JPMarkDown = require('jp-markdown');
const parser = new JPMarkDown();
const html = parser.Parse('# Hello\n\nSome **bold** text.');
console.log(html);
// => <h1>Hello</h1><p>Some <strong>bold</strong> text.</p>Embed in an existing page (recommended)
When you already have your own layout and CSS, return an HTML fragment and let JP-MarkDown handle code styling separately:
const html = parser.Parse(markdown, {
fullDocument: false, // no <!DOCTYPE html> wrapper
includeStyle: false, // skip default document CSS
includeCodeStyle: true, // inject scoped code-block CSS
includeCodeScript: true, // enable copy-to-clipboard buttons
});This is the most common setup for Express, Next.js API routes, or any app that renders markdown into a template.
Code blocks
Fenced code blocks are syntax-highlighted with a GitHub Dark theme (overridable), line numbers, a language label, and a copy button.
Markdown input:
```js
const html = parser.Parse(markdown, {
fullDocument: false,
includeStyle: false,
});
```What you get:
- Syntax-highlighted tokens (via highlight.js)
- Language header (e.g.
JavaScript,Lua) - Line numbers (flat rows, no per-line boxes)
- One-click Copy button
- Scoped CSS injected when
includeCodeStyle: true
Supported language tags include js, ts, python, lua, bash, json, html, css, and any language highlight.js recognizes. Unknown tags fall back to plain text.
Theming with CSS variables
When you ship your own stylesheet (recommended: includeCodeStyle: false + import jp-markdown/code.css), override these on :root or a parent:
| Variable | Role |
|---|---|
| --jp-md-bg | Block background |
| --jp-md-header-bg | Header bar |
| --jp-md-border | Outer / header borders |
| --jp-md-line-bg | Unused (lines are transparent) |
| --jp-md-line-border | Unused (no per-line boxes) |
| --jp-md-muted | Lang label + line numbers |
| --jp-md-fg | Default code color |
| --jp-md-copy-bg | Copy button background |
| --jp-md-copy-hover-bg | Copy button hover fill |
| --jp-md-copy-hover-border | Copy button hover border |
Also honors --font-mono / --font-sans when set by the host app.
Inline code
Inline `code` spans use your elementStyles.code classes if configured, otherwise the built-in jp-md-inline-code class.
Constructor options
Create one shared instance and reuse it across your app:
const parser = new JPMarkDown({
// Per-element Tailwind / CSS classes
elementStyles: {
h1: { class: 'text-4xl font-bold text-white mb-4' },
p: { class: 'text-gray-300 leading-relaxed mb-4' },
code: { class: 'bg-gray-900 text-green-400 px-1 rounded font-mono text-sm' },
a: { class: 'text-blue-400 underline' },
},
// Code block behaviour
codeCopyButton: true, // show copy button (default: true)
codeLineNumbers: true, // show line numbers (default: true)
// Document-level CSS (only when includeStyle + addCustomCSS are true)
addCustomCSS: false,
injectCSS: true,
customCSS: 'body { background: #111; }',
// Override individual token renderers
customRender: {
h1: (text) => `<h1 class="my-heading">${text}</h1>`,
},
});| Option | Default | Description |
|--------|---------|-------------|
| elementStyles | {} | Map of tag → { class, style } applied to headings, paragraphs, links, etc. |
| customRender | {} | Replace render functions for specific tags (h1–h6, p, a, codeblock, …) |
| codeCopyButton | true | Show copy button on fenced code blocks |
| codeLineNumbers | true | Show line numbers on fenced code blocks |
| addCustomCSS | false | Enable default document CSS injection |
| injectCSS | true | Prepend document CSS to fragment output |
| customCSS | '' | Extra CSS appended to the document style block |
| defaultCSS | built-in dark theme | Override the default document stylesheet |
| markedOptions | {} | Extra options passed to marked.setOptions() |
Parse options
parser.Parse(markdown, {
fullDocument: false,
includeStyle: false,
includeCodeStyle: true,
includeCodeScript: true,
title: 'My Document',
autoExport: false,
exportPath: './output.html',
});| Option | Default | Description |
|--------|---------|-------------|
| fullDocument | false | Wrap output in a full <!DOCTYPE html> document |
| includeStyle | true | Inject document CSS (requires addCustomCSS: true on the instance) |
| includeCodeStyle | true | Inject scoped code-block CSS — works even when includeStyle: false |
| includeCodeScript | true | Inject copy-button script (only when code blocks are present) |
| title | 'JP-MarkDown Document' | <title> used when fullDocument: true |
| autoExport | false | Write rendered HTML to disk |
| exportPath | './output.html' | File path used when autoExport: true |
External CSS & JS (no inline injection)
If you prefer to load assets once in your layout instead of injecting them per render:
const html = parser.Parse(markdown, {
fullDocument: false,
includeStyle: false,
includeCodeStyle: false, // don't inject <style>
includeCodeScript: false, // don't inject <script>
});Then in your HTML layout:
<link rel="stylesheet" href="/path/to/node_modules/jp-markdown/code.css">
<script src="/path/to/node_modules/jp-markdown/code.js" defer></script>Or copy those files into your static assets folder.
Alert blocks
JP-MarkDown supports custom alert syntax (in addition to standard markdown):
:::info
This is an informational message.
:::
:::warning
Be careful with this setting.
:::
:::danger
This action cannot be undone.
:::
:::note
A quick side note for the reader.
:::Each renders as a styled alert <div> with an icon and label.
Full HTML document export
Generate a standalone HTML file:
parser.Parse('# My Report\n\nContent here.', {
fullDocument: true,
includeStyle: true,
title: 'My Report',
autoExport: true,
exportPath: './report.html',
});
// => writes report.html and returns the HTML stringEnable document CSS on the instance first:
const parser = new JPMarkDown({ addCustomCSS: true });TypeScript
Type definitions are included:
import JPMarkDown from 'jp-markdown';
const parser = new JPMarkDown({
elementStyles: {
h1: { class: 'text-4xl font-bold' },
},
});
const html: string = parser.Parse('# Hello', {
fullDocument: false,
includeCodeStyle: true,
});Real-world example (Express / EJS)
// utils/markdown.js
const JPMarkDown = require('jp-markdown');
const parser = new JPMarkDown({
elementStyles: {
h1: { class: 'text-5xl font-black mb-6 text-white' },
p: { class: 'text-gray-300 mb-6 leading-relaxed' },
code: { class: 'bg-gray-900 text-green-400 px-1.5 py-0.5 rounded font-mono text-sm' },
},
});
function renderMarkdown(md) {
return parser.Parse(String(md || ''), {
fullDocument: false,
includeStyle: false,
includeCodeStyle: true,
includeCodeScript: true,
});
}
module.exports = { renderMarkdown };<!-- article.ejs -->
<article class="docs-article">
<%- articleHtml %>
</article>API summary
const JPMarkDown = require('jp-markdown');
// 1. Create a configured instance (reuse it)
const parser = new JPMarkDown(options);
// 2. Parse markdown to HTML
const html = parser.Parse(markdownString, parseOptions);Dependencies
- marked — Markdown parsing (GFM)
- highlight.js — Server-side syntax highlighting
License
MIT © Jipy
