A lightweight, dependency-minimal JavaScript library for converting Markdown to themed HTML directly in the browser.
- GitHub Flavored Markdown - Full GFM support including tables, task lists, and strikethrough
- Three Built-in Themes - Light, dark, and fully customizable themes
- XSS Protection - Built-in HTML sanitization with DOMPurify
- Zero Server Required - Runs entirely in the browser
- Lightweight - Minimal dependencies, optimized bundle size
- Accessible - WCAG-compliant UI with keyboard navigation
- Responsive - Mobile-friendly interface
- Fast - Instant live preview with theme switching
NPM (Recommended):
npm install md2html-themes
npm install --save-dev vite # Development server (required)Yarn:
yarn add md2html-themes
yarn add --dev viteCDN (No build tools required):
<script src="https://unpkg.com/md2html-themes@latest/dist/md2html.min.js"></script>π¦ NPM Package: md2html-themes
This package uses ES modules (import/export). Modern browsers require ES modules to be served over HTTP, not opened directly as files (file:// protocol).
Vite provides:
- β‘ Instant server start (no bundling in dev)
- π₯ Hot Module Replacement (instant updates)
- π¦ Zero configuration
- π Optimized production builds
Alternative servers: http-server, serve, Python's http.server, or VS Code Live Server extension will also work, but Vite provides the best developer experience.
This example is production-ready and can be copied directly:
mkdir my-md2html-app
cd my-md2html-app
npm init -y
npm install md2html-themes
npm install --save-dev vitepackage.json:
{
"name": "my-md2html-app",
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"md2html-themes": "^1.1.1"
},
"devDependencies": {
"vite": "^5.0.0"
}
}Important: "type": "module" enables ES module support.
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>md2html Example</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
#output {
border: 1px solid #ccc;
padding: 20px;
margin: 20px 0;
border-radius: 8px;
}
button {
background: #007bff;
color: white;
border: none;
padding: 10px 20px;
margin: 5px;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #0056b3;
}
</style>
</head>
<body>
<h1>md2html Converter</h1>
<button id="convert">Convert Markdown</button>
<button id="theme-light">Light Theme</button>
<button id="theme-dark">Dark Theme</button>
<div id="output"></div>
<!-- CRITICAL: Must use type="module" for ES modules -->
<script type="module" src="index.js"></script>
</body>
</html>index.js:
// Import the package
import md2html from 'md2html-themes';
console.log('md2html loaded successfully!');
// Sample markdown
const markdown = `# Hello World
This is a **test** of the *md2html-themes* package.
## Features:
- β
Markdown parsing
- β
Theme support
- β
Live preview
\`\`\`javascript
console.log('Code blocks work too!');
\`\`\`
> This is a blockquote
| Feature | Status |
|---------|--------|
| Working | β
|
`;
// Convert button
document.getElementById('convert').addEventListener('click', async () => {
try {
const result = await md2html.parse(markdown);
const output = document.getElementById('output');
output.innerHTML = result.html;
console.log('Conversion successful!');
} catch (error) {
console.error('Conversion failed:', error);
}
});
// Light theme button
document.getElementById('theme-light').addEventListener('click', () => {
const output = document.getElementById('output');
// NEW in v1.1.1: Automatic CSS injection - no manual CSS needed!
md2html.applyThemeWithStyles(md2html.themes.light, output);
console.log('Light theme applied');
});
// Dark theme button
document.getElementById('theme-dark').addEventListener('click', () => {
const output = document.getElementById('output');
// NEW in v1.1.1: Automatic CSS injection
md2html.applyThemeWithStyles(md2html.themes.dark, output);
console.log('Dark theme applied');
});
// Auto-convert on page load
window.addEventListener('load', () => {
document.getElementById('convert').click();
setTimeout(() => document.getElementById('theme-light').click(), 500);
});npm run devOutput:
VITE v5.x.x ready in 250 ms
β Local: http://localhost:5173/
β press h to show help
Open http://localhost:5173 in your browser. You'll see:
- Markdown automatically converted to HTML
- Light theme applied by default
- Clickable buttons to switch themes
- Any code changes trigger instant HMR updates
β οΈ Important: Cannot openindex.htmldirectly (file://protocol). Must use a development server due to ES module CORS restrictions.
import md2html from 'md2html-themes';
// Parse markdown
const result = await md2html.parse('# Hello World\n\nThis is **bold** text.');
// Display in your web page
const preview = document.getElementById('preview');
preview.innerHTML = result.html;
// NEW in v1.1.1: Apply theme with automatic CSS injection (recommended)
md2html.applyThemeWithStyles(md2html.themes.dark, preview);
// Or use legacy method (requires manual CSS - not recommended)
md2html.applyTheme(md2html.themes.dark);
// Or generate a complete standalone HTML document
const fullHtml = md2html.toFullHtml(
result.html,
md2html.themes.dark,
{ title: 'My Document', inlineStyles: true }
);<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>md2html Demo</title>
</head>
<body>
<div id="preview"></div>
<!-- Load from CDN -->
<script src="https://unpkg.com/md2html-themes@latest/dist/md2html.min.js"></script>
<script>
// md2html is now available as a global variable
(async () => {
const result = await md2html.parse('# Hello from CDN!\n\n**No build step required!**');
const preview = document.getElementById('preview');
preview.innerHTML = result.html;
// NEW in v1.1.0: Automatic CSS injection - no manual CSS needed!
md2html.applyThemeWithStyles(md2html.themes.light, preview);
})();
</script>
</body>
</html>Comprehensive documentation is available in the /docs directory:
- Installation Guide - π¦ NPM, CDN, and installation methods
- Usage Guide - π Detailed usage examples and code snippets
- API Reference - Complete API documentation
- Introduction - Overview and features
- Theme Schema - Theme customization guide
- Testing - Testing strategy and guidelines
- Extending to PDF - Future PDF export plans
- Manual Test Cases - QA checklist
md2html/
βββ src/
β βββ index.js # Public API
β βββ parser.js # Markdown parsing
β βββ sanitizer.js # XSS protection
β βββ theme.js # Theme engine
β βββ ui/
β β βββ demo.js # Demo application
β β βββ components/ # UI components
β βββ styles/ # CSS themes
βββ public/
β βββ index.html # Demo page
βββ tests/
β βββ unit/ # Unit tests
β βββ e2e/ # E2E tests
βββ docs/ # Documentation
βββ samples/ # Sample markdown files
βββ dist/ # Built files
# Start development server
npm run start
# Build for production
npm run build
# Run unit tests
npm test
# Run E2E tests
npm run test:e2e
# Run linter
npm run lintRuntime:
- marked - Markdown parser (chosen for lightweight footprint and GFM support)
- DOMPurify - XSS sanitization
Development:
- Vite - Dev server and build tool
- Vitest - Unit testing
- Playwright - E2E testing
- Rollup - Library bundling
marked: Lightweight (~50KB), fast, well-maintained, excellent GFM support, and highly extensible.
DOMPurify: Industry standard for HTML sanitization, actively maintained, comprehensive XSS protection.
- Headings (H1-H4)
- Paragraphs and line breaks
- Bold, italic,
strikethrough - Links and images
- Ordered and unordered lists
- Nested lists
- Task lists (- [ ] Todo)
- Tables with alignment
- Code blocks with language tags
- Inline
code - Blockquotes
- Horizontal rules
- Frontmatter (YAML)
- Light - Clean, professional light theme
- Dark - Eye-friendly dark theme
- Custom - Fully editable theme with live preview
Recommended for most users - CSS styles are automatically injected:
// No manual CSS required! Everything is handled automatically.
md2html.applyThemeWithStyles(md2html.themes.dark, container);<!DOCTYPE html>
<html>
<body>
<div id="output"></div>
<script src="https://unpkg.com/md2html-themes@latest/dist/md2html.min.js"></script>
<script>
(async () => {
const result = await md2html.parse('# Hello World\n\nThis is **bold** text.');
const output = document.getElementById('output');
output.innerHTML = result.html;
// Magic! CSS styles are automatically included - no manual CSS needed!
md2html.applyThemeWithStyles(md2html.themes.light, output);
})();
</script>
</body>
</html>For advanced users who want full control over styling:
// Sets CSS variables - you provide the CSS that uses them
md2html.applyTheme(md2html.themes.dark, container);<style>
.my-markdown {
color: var(--color-text);
background: var(--color-surface);
font-family: var(--font-family);
/* ... more CSS using the variables ... */
}
</style>// Clone and customize
const myTheme = md2html.cloneTheme(md2html.themes.light);
myTheme.colors.background = '#fef3c7';
myTheme.colors.text = '#78350f';
myTheme.typography.baseFontSize = '18px';
// Apply with automatic CSS (recommended)
md2html.applyThemeWithStyles(myTheme, container);
// Or apply with manual CSS variables
md2html.applyTheme(myTheme);
// Export and import
const json = md2html.exportTheme(myTheme);
localStorage.setItem('myTheme', json);
const savedTheme = md2html.importTheme(json);
md2html.applyThemeWithStyles(savedTheme, container);See Theme Schema for complete customization options.
md2html includes built-in XSS protection via DOMPurify. All HTML output is sanitized by default to prevent script injection and other attacks.
// Sanitization is enabled by default
const result = await md2html.parse(markdown);
// Check for dangerous content
if (md2html.hasDangerousContent(html)) {
console.warn('Content contains potentially dangerous HTML');
}See samples/sample-xss.md for tested attack vectors.
- Chrome/Edge 90+
- Firefox 88+
- Safari 14+
- Mobile browsers (iOS Safari, Chrome Mobile)
Uses modern JavaScript features:
- ES Modules
- Async/await
- CSS Custom Properties
- Fetch API
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for new functionality
- Run tests (
npm test) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
# Run all tests
npm test
# Run with coverage
npm test -- --coverage
# Run E2E tests
npm run test:e2e
# Run in watch mode
npm test -- --watchSee Testing Documentation for details.
MIT Β© 2025
See LICENSE for details.
- PDF export (Puppeteer-based)
- Syntax highlighting for code blocks
- Math rendering (KaTeX)
- Mermaid diagram support
- Custom renderer hooks
- React/Vue wrapper components
- VS Code extension
- CLI tool
Built with β€οΈ using vanilla JavaScript