Lightweight, block-based markdown solution (zero dependencies). Parse, create, serialize, and render markdown with TypeScript support.
| Package | Version | Description |
|---|---|---|
| @create-markdown/core | 0.2.0 | Zero-dependency parsing and serialization |
| @create-markdown/react | 0.2.0 | React components and hooks |
| @create-markdown/preview | 1.0.0 | HTML rendering with themes, plugins, and BYO-parser support |
| @create-markdown/mdx | 0.2.0 | MDX conversion |
| create-markdown | 0.4.0 | Convenience bundle |
- Block-based architecture: Work with structured blocks instead of raw strings
- Bidirectional conversion: Parse markdown to blocks, serialize blocks to markdown
- Rich inline styles: Bold, italic, code, links, strikethrough, highlights
- React components: Optional React bindings for rendering and editing
- HTML preview: Framework-agnostic HTML rendering with themes
- BYO parser: Use
applyPreviewTheme()withmarked,markdown-it,remark, or any parser -- no lock-in to@create-markdown/core - CSS custom property theming:
system.csstheme integrates with any design system via--cm-*variables - Syntax highlighting: Shiki plugin for code blocks
- Diagrams: Mermaid plugin for flowcharts, sequence diagrams, etc.
- Web Component:
<markdown-preview>custom element with optional light DOM mode - BYO sanitizer: Plug in DOMPurify or any sanitizer function
- Theme CSS as strings: Import theme CSS as string constants for CSS-in-JS or web components
- Zero dependencies: Core package has no runtime dependencies
- Full TypeScript: Complete type definitions with generics
# Install individual packages (recommended)
pnpm add @create-markdown/core
pnpm add @create-markdown/react
pnpm add @create-markdown/preview
# Or install the convenience bundle
pnpm add create-markdownimport { parse, stringify, h1, paragraph } from '@create-markdown/core';
// Parse markdown to blocks
const blocks = parse('# Hello\n\nWorld');
// Create blocks programmatically
const doc = [
h1('Hello'),
paragraph('World'),
];
// Serialize back to markdown
const markdown = stringify(doc);@create-markdown/preview works with any parser's HTML output -- no need to switch to @create-markdown/core:
import { applyPreviewTheme } from '@create-markdown/preview';
import { marked } from 'marked';
const raw = marked.parse('# Hello\n\nSome **bold** text.');
const themed = applyPreviewTheme(raw); // wraps elements with cm-* classesPair with any theme CSS (github.css, github-dark.css, minimal.css, or system.css) and the styled output just works.
import { BlockRenderer, useDocument, paragraph } from '@create-markdown/react';
function Editor() {
const doc = useDocument([paragraph('Start typing...')]);
return (
<div>
<BlockRenderer blocks={doc.blocks} />
<button onClick={() => doc.appendBlock(paragraph('New paragraph'))}>
Add Paragraph
</button>
</div>
);
}import { renderAsync, shikiPlugin, mermaidPlugin } from '@create-markdown/preview';
import { parse } from '@create-markdown/core';
const blocks = parse(`
# Code Example
\`\`\`typescript
const x = 42;
\`\`\`
\`\`\`mermaid
flowchart LR
A --> B --> C
\`\`\`
`);
const html = await renderAsync(blocks, {
plugins: [shikiPlugin(), mermaidPlugin()],
});The system.css theme uses CSS custom properties so it adapts to any design system:
/* Set once -- the theme adapts to light and dark mode automatically */
:root {
--cm-text: #1f2328;
--cm-bg: #ffffff;
--cm-border: #d1d9e0;
--cm-code-bg: #f6f8fa;
--cm-link: #0969da;
}
@media (prefers-color-scheme: dark) {
:root {
--cm-text: #e6edf3;
--cm-bg: #0d1117;
--cm-border: #30363d;
--cm-code-bg: #161b22;
--cm-link: #58a6ff;
}
}import '@create-markdown/preview/themes/system.css';Pass any sanitizer function instead of relying on a built-in implementation:
import { blocksToHTML } from '@create-markdown/preview';
import DOMPurify from 'dompurify';
const html = blocksToHTML(blocks, {
sanitize: (html) => DOMPurify.sanitize(html, { USE_PROFILES: { html: true } }),
});Import theme CSS as string constants for CSS-in-JS, bundlers that struggle with CSS imports, or web components:
import { themes } from '@create-markdown/preview/themes';
// themes.github, themes.githubDark, themes.minimal, themes.system
const style = document.createElement('style');
style.textContent = themes.githubDark;
document.head.appendChild(style);<script type="module">
import { registerPreviewElement } from '@create-markdown/preview';
registerPreviewElement();
</script>
<markdown-preview theme="github-dark">
# Hello World
This renders automatically!
</markdown-preview>Use shadowMode: 'none' to render in the light DOM and inherit page styles:
registerPreviewElement({ shadowMode: 'none' });| Document | Description |
|---|---|
| packages/core/README.md | Core API reference |
| packages/react/README.md | React components guide |
| packages/preview/README.md | Preview and plugins guide |
| ROADMAP.md | Feature roadmap |
| CONTRIBUTING.md | Contribution guidelines |
| INTEGRATION.md | Framework integrations |
# Install dependencies
pnpm install
# Build all packages
pnpm run build
# Run tests
pnpm run test
# Type check
pnpm run typecheck
# Run the playground
pnpm run playgroundcreate-markdown/
├── packages/
│ ├── core/ # @create-markdown/core
│ ├── react/ # @create-markdown/react
│ ├── preview/ # @create-markdown/preview
│ ├── mdx/ # @create-markdown/mdx
│ ├── create-markdown/ # Convenience bundle
│ └── docs/ # Documentation site
├── playground/ # Demo application
├── scripts/ # Release and utility scripts
└── .github/ # CI/CD workflows
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
MIT