Skip to content

Repository files navigation

Draftly

A modern, extensible markdown editor and previewer for the web.

npm versionnpm downloadslicenseGitHub starsTypeScriptCodeMirror 6

InstallationQuick StartUsageFeaturesAPILicense


Overview

Draftly is a powerful, pluggable markdown editor and preview toolkit built on top of CodeMirror 6. It provides a seamless "rich text" editing experience while preserving standard markdown syntax. Draftly also includes a static HTML renderer that produces output visually identical to the editor, making it perfect for blogs, documentation sites, and content management systems.

Why Draftly?

  • 🚀 Modern Architecture: Built on CodeMirror 6 with incremental Lezer parsing.
  • 🎨 Rich Editing: WYSIWYG-like experience with full markdown control.
  • 🔌 Extensible Plugin System: Add custom rendering, keymaps, and syntax.
  • 🖼️ Static Preview: Render markdown to semantic HTML with visual parity.
  • 🌗 Theming: First-class support for light and dark modes.
  • 📦 Modular Exports: Import only what you need (draftly/editor, draftly/preview, draftly/plugins).

Installation

Install the package via your preferred package manager:

# npm
npm install draftly
# yarn
yarn add draftly
# pnpm
pnpm add draftly
# bun
bun add draftly

Peer Dependencies

Draftly requires the following CodeMirror packages as peer dependencies. Make sure they are installed in your project:

npm install @codemirror/commands @codemirror/lang-markdown @codemirror/language @codemirror/language-data @codemirror/state @codemirror/view

Quick Start

Get up and running in seconds.

import{EditorView}from"@codemirror/view";import{EditorState}from"@codemirror/state";import{draftly}from"draftly";constview=newEditorView({state: EditorState.create({doc: "# Hello, Draftly!",extensions: [draftly()],}),parent: document.getElementById("editor")!,});

Usage

Draftly is designed for flexibility. Use it as a CodeMirror extension for interactive editing or as a standalone renderer for static previews.

Editor Integration

Here's a complete example using @uiw/react-codemirror:

importCodeMirrorfrom"@uiw/react-codemirror";import{draftly,allPlugins,ThemeEnum}from"draftly";import{githubDark}from"@uiw/codemirror-theme-github";functionMarkdownEditor(){return(<CodeMirrorvalue="# Welcome to Draftly\n\nStart writing..."height="500px"extensions={[draftly({theme: ThemeEnum.DARK,themeStyle: githubDark,plugins: allPlugins,lineWrapping: true,history: true,indentWithTab: true,onNodesChange: (nodes)=>console.log("AST:",nodes),}),]}/>);}

Editor Configuration (DraftlyConfig)

OptionTypeDefaultDescription
themeThemeEnumThemeEnum.AUTOTheme mode: LIGHT, DARK, or AUTO.
themeStyleExtensionundefinedCodeMirror theme extension (e.g., githubDark).
pluginsDraftlyPlugin[][]Plugins to enable for rendering and parsing.
baseStylesbooleantrueLoad default base styles.
disableViewPluginbooleanfalseDisable rich rendering (raw markdown mode).
defaultKeybindingsbooleantrueEnable default CodeMirror keybindings.
historybooleantrueEnable undo/redo history.
indentWithTabbooleantrueUse Tab for indentation.
highlightActiveLinebooleantrueHighlight the current line (in raw mode).
lineWrappingbooleantrueEnable line wrapping.
onNodesChange(nodes: DraftlyNode[]) => voidundefinedCallback fired on every document update with parsed AST.
markdownMarkdownConfig[][]Additional Lezer markdown parser extensions.
extensionsExtension[][]Additional CodeMirror extensions.
keymapKeyBinding[][]Additional keybindings.

Static Preview

Render markdown to semantic HTML for server-side rendering, static site generation, or read-only views.

import{preview,generateCSS,allPlugins,ThemeEnum}from"draftly";constmarkdown=`# Hello WorldThis is a **bold** statement with some \`inline code\`.- Item 1- Item 2- Item 3`;// Generate HTMLconsthtml=preview(markdown,{theme: ThemeEnum.LIGHT,plugins: allPlugins,sanitize: true,wrapperClass: "prose",});// Generate matching CSSconstcss=generateCSS({theme: ThemeEnum.LIGHT,plugins: allPlugins,wrapperClass: "prose",includeBase: true,});// Use in your appfunctionArticlePreview(){return(<><style>{css}</style><articledangerouslySetInnerHTML={{__html: html}}/></>);}

Preview Configuration (PreviewConfig)

OptionTypeDefaultDescription
pluginsDraftlyPlugin[][]Plugins for rendering.
themeThemeEnumThemeEnum.AUTOTheme mode.
sanitizebooleantrueSanitize HTML output (via DOMPurify).
wrapperClassstring"draftly-preview"CSS class for the wrapper element.
wrapperTagstring"article"HTML tag for the wrapper element.
markdownMarkdownConfig[][]Additional parser extensions.

Features

🎯 Rich Text Editing

Draftly's ViewPlugin decorates the editor to hide markdown syntax and render styled content inline. This provides a WYSIWYG-like experience while keeping the source as plain markdown.

  • Inline Formatting: Bold, italic, strikethrough, and code are styled in-place.
  • Headings: Rendered with proper sizes and weights.
  • Lists: Ordered and unordered lists with custom bullets.
  • Images: Displayed inline with alt text and captions.
  • Links: Clickable with visual distinction.
  • Code Blocks: Syntax highlighted with language detection.

🔌 Plugin Architecture

Every feature in Draftly is a plugin. Plugins can provide:

  • CodeMirror Extensions: Custom decorations, widgets, and behaviors.
  • Markdown Parser Extensions: Extend the Lezer parser for custom syntax.
  • Keymaps: Add keyboard shortcuts.
  • Themes: Inject custom styles based on the current theme.
  • Preview Renderers: Define how elements are rendered to static HTML.
import{DraftlyPlugin}from"draftly/editor";classMyCustomPluginextendsDraftlyPlugin{name="my-custom-plugin";onRegister(context){console.log("Plugin registered!",context.config);}getExtensions(){return[/* CodeMirror extensions */];}getKeymap(){return[/* KeyBinding[] */];}getMarkdownConfig(){return{/* MarkdownConfig */};}theme(mode){return{/* Theme spec */};}}

🌲 AST Access

Access the parsed document structure via the onNodesChange callback. Perfect for building:

  • Table of Contents
  • Document Outlines
  • Navigation Breadcrumbs
  • Word/Line Counters
typeDraftlyNode={from: number;// Start positionto: number;// End positionname: string;// Node type (e.g., "Heading", "Paragraph")children: DraftlyNode[];isSelected: boolean;// True if cursor is within this node};

🌗 Theming

Draftly provides seamless theming with automatic light/dark mode support:

  • Auto Detection: Follows system preference with ThemeEnum.AUTO.
  • Manual Control: Force ThemeEnum.LIGHT or ThemeEnum.DARK.
  • Custom Themes: Pass any CodeMirror theme via themeStyle.
  • Preview Parity: CSS generation ensures preview matches editor styling.

📦 Modular Imports

Import only what you need to minimize bundle size:

// Full packageimport{draftly,preview,allPlugins}from"draftly";// Editor onlyimport{draftly,DraftlyPlugin}from"draftly/editor";// Preview onlyimport{preview,generateCSS}from"draftly/preview";// Individual pluginsimport{HeadingPlugin,ListPlugin}from"draftly/plugins";

API Reference

Exports

ExportPathDescription
draftlydraftly/editorMain editor extension factory.
DraftlyPlugindraftly/editorBase class for creating plugins.
ThemeEnumdraftly/editorEnum for theme modes (AUTO, LIGHT, DARK).
DraftlyNodedraftly/editorType for AST nodes.
previewdraftly/previewFunction to render markdown to HTML.
generateCSSdraftly/previewFunction to generate CSS for preview styling.
allPluginsdraftly/pluginsArray of all built-in plugins.

Browser Support

Draftly supports all modern browsers:

BrowserVersion
Chrome88+
Firefox78+
Safari14+
Edge88+

Contributing

Contributions are welcome! Please read our Contributing Guide before submitting a pull request.


License

MIT © NeuroNexul

About

A modern, intuitive Markdown editor built on the powerful CodeMirror 6 framework, designed to bring a truly What You See Is What You Get experience

Topics

Resources

Contributing

Security policy

Stars

45 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages