A headless, AST-driven Markdown editor engine — built for makers who need real Markdown, not another WYSIWYG.
Powered by CodeMirror 6 + the unified ecosystem. Framework-agnostic core · Official React & Vue bindings · MIT licensed.
中文文档 · Quick Start · Why Nexus? · Roadmap · Contributing
We ship in priority tiers — P0 is what we're working on right now.
| Tier | Theme | Highlights |
|---|---|---|
| P0 — Now | Core API completeness | getSelectedText(), slash command sorting, <Editor /> onReady, TS strict coverage |
| P1 — Next | Power-user features | Multi-cursor, regex search, undo/redo grouping, widget API standardization, Electron packaging |
| P2 — Mid-term | UX & ecosystem | Advanced toolbar (emoji / table / color), fuzzy search, sync-scroll preview, web-component wrapper |
| P3 — Long-term | Collaboration | Realtime CRDT collab, shared comments / @mention, plugin hot-reload |
👉 Full roadmap with package ownership, status, and OpenSpec linkage: docs/ROADMAP.md
Markdown editing on the web is a crowded space — yet every existing option forced us to compromise on something fundamental. We built Nexus because we needed an editor that treats Markdown text as a first-class document, not a JSON shadow copy that only occasionally gets serialized back to .md.
| Nexus | Tiptap | Lexical | Milkdown | MDXEditor | @uiw/react-md-editor | |
|---|---|---|---|---|---|---|
| Foundation | CodeMirror 6 + unified | ProseMirror | Built from scratch (Meta) | ProseMirror + Remark | Lexical | CodeMirror + Marked |
| Source of truth | Markdown text | JSON tree | JSON tree | ProseMirror doc | Lexical state | Markdown text |
| Round-trip safe | ✅ Lossless | ✅ | ||||
| UI model | Headless | Headless | Headless-ish | WYSIWYG (built-in UI) | WYSIWYG | Split-pane |
| Live preview | Obsidian-style inline | None (BYO) | None (BYO) | Full WYSIWYG | Full WYSIWYG | Side-by-side pane |
| Framework support | React · Vue · Vanilla | React · Vue · Svelte · Vanilla | React-first | React · Vue · Vanilla | React only | React only |
| Plugin tiers | 3 (shortcut / AST / CM6) | 1 (Tiptap extension) | 1 (node + transform) | 1 (Milkdown plugin) | 1 (Lexical plugin) | None |
| Bundle (core, approx.) | Small (CM6 ~110KB) | Medium (PM + ext.) | ~22KB core | ~125KB / ~40KB gz | ~851KB gz | Medium |
| Local-first / file IO hooks | ✅ First-class | ❌ | ❌ | ❌ | ❌ | ❌ |
| License | MIT | MIT (+ paid cloud) | MIT | MIT | MIT | MIT |
Numbers are taken from public docs and recent third-party reviews. Bundle sizes vary with plugins enabled — treat the column as a rough order-of-magnitude.
- Tiptap / Lexical / Milkdown / MDXEditor all keep an internal JSON document model. Markdown is an import/export concern — round-tripping a
.mdfile through them can quietly drift (lost soft-breaks, ordering nuances, custom syntax). - @uiw/react-md-editor keeps Markdown as the document, but offers a classic split-pane preview — no inline syntax reveal, no widget API, React only.
- Obsidian has the UX we love, but it's closed source. You can't embed its engine in your own product.
- Nexus keeps Markdown as the document and gives you Obsidian-style live preview, a widget API, three plugin altitudes, and framework-agnostic bindings — without the WYSIWYG lock-in.
If you're building a note-taking app, a docs CMS, a static-site authoring tool, a Markdown-native PKM, or an LLM-powered writing assistant, Nexus is meant to be the engine you don't have to fight.
# pnpm (recommended)
pnpm add @floatboat/nexus-core @floatboat/nexus-preset-gfm
# or npm / yarn
npm install @floatboat/nexus-core @floatboat/nexus-preset-gfmReact — the fast path
import { Editor } from "@floatboat/nexus-react";
import { createGfmPreset } from "@floatboat/nexus-preset-gfm";
export default function App() {
return (
<Editor
initialValue="# Hello, Nexus 👋"
plugins={[createGfmPreset()]}
livePreview
onChange={(doc, ast) => console.log(doc)}
/>
);
}💡 New to CodeMirror? You don't need to know it.
<Editor />handles the lifecycle — just drop it in.
Vue 3
<script setup>
import { Editor } from "@floatboat/nexus-vue";
import { createGfmPreset } from "@floatboat/nexus-preset-gfm";
</script>
<template>
<Editor
initial-value="# Hello"
:plugins="[createGfmPreset()]"
:live-preview="true"
@change="(doc) => console.log(doc)"
/>
</template>Vanilla / Plain DOM
import { createEditor } from "@floatboat/nexus-core";
import { createGfmPreset } from "@floatboat/nexus-preset-gfm";
import { createHistoryPlugin } from "@floatboat/nexus-plugin-history";
const editor = createEditor({
container: document.getElementById("editor")!,
initialValue: "# Hello\n\nStart typing...",
plugins: [createGfmPreset(), createHistoryPlugin()],
livePreview: true,
onChange(doc, ast) {
console.log("Markdown:", doc);
console.log("AST:", ast);
},
});🐣 Things we wish someone had told us when we started
- You don't need to know CodeMirror. The React / Vue wrapper handles the lifecycle. You only meet CodeMirror if you write a low-level plugin.
- Headless means no theme. We ship logic, not looks. Plan a few hours for styling — the Electron demo is a copy-pasteable starting point.
- Live preview is opt-in. If you just want a raw Markdown editor, leave it off and you get a clean text-editing experience.
- The AST is
mdast— the same tree used byremarkand the unified ecosystem. If you've never seen it, the mdast spec is the one-page cheat sheet you need.- Don't auto-save on every keystroke.
onChangefires constantly — debounce before writing to disk or hitting the network.- Blank screen? Nine times out of ten, the container has no height. Give it one and the editor appears.
- Lost? Open an issue with the
questionlabel — we'd rather answer the same question 20 times than have you give up.
git clone https://github.com/floatboatai/Nexus-Editor.git
cd Nexus-Editor
pnpm install
pnpm dev:electron-demoA real Electron app with file IO, live preview, and every plugin enabled — the fastest way to see what's possible.
Full package list (11 packages) — click to expand
| Package | Description |
|---|---|
@floatboat/nexus-core |
Editor engine — CM6 state, AST pipeline, live preview, events, widget API |
@floatboat/nexus-react |
React binding — useEditor hook and <Editor /> component |
@floatboat/nexus-vue |
Vue 3 binding — useEditor composable |
@floatboat/nexus-preset-gfm |
GitHub Flavored Markdown preset (tables, strikethrough, task lists) |
@floatboat/nexus-plugin-history |
Undo/redo with Ctrl+Z / Ctrl+Shift+Z |
@floatboat/nexus-plugin-search |
Search and replace helpers |
@floatboat/nexus-plugin-slash |
Slash command detection, ranking, and a vanilla-DOM floating menu UI |
@floatboat/nexus-plugin-toolbar |
Toolbar primitives for formatting commands |
@floatboat/nexus-plugin-math |
Inline / block math rendering (KaTeX) |
@floatboat/nexus-plugin-vim |
Vim keybindings powered by @replit/codemirror-vim |
@floatboat/nexus-plugin-wordcount |
Markdown-aware word / character / CJK / reading-time stats + ARIA-live status bar |
- Headless — no built-in UI. Render with any framework or plain DOM.
- AST-Driven — real-time Markdown → mdast parsing with every keystroke.
- Live Preview — inline rendering that reveals raw syntax on cursor focus (Obsidian-style).
- Plugin System — three tiers: shortcuts & slash commands, remark plugins & widgets, raw CM6 extensions.
- Event System — subscribe to
change,focus,blur,selectionChange,slashMenuChange. - Widget API — render custom components for any AST node type (code blocks, tables, diagrams).
- Local-First — built for Electron/Tauri with file IO hooks and debounced parsing.
Plugin platform documentation (Chinese): native plugin API · Obsidian migration matrix · legacy migration
Editor API — methods and events
createEditor(config) returns an EditorAPI with:
editor.getDocument() // current Markdown string
editor.getAst() // current mdast Root
editor.setDocument(md) // replace entire document
editor.setDocument(md, { silent: true, preserveSelection: true })
editor.setDocument(md, { selection: { anchor: 0 } })
editor.setSelection(pos) // move cursor
editor.focus() / editor.blur()
editor.destroy()
// Event system
editor.on("change", (doc, ast) => { ... })
editor.on("selectionChange", ({ anchor, head }) => { ... })
editor.on("slashMenuChange", ({ isOpen, query, commands, coords }) => { ... })
editor.off("change", handler)
// Coordinates (for floating UI)
editor.getCoordsAtPos(pos) // { left, right, top, bottom } | nullPlugin authoring — three tiers, one shape
const myPlugin: NexusPlugin = {
name: "my-plugin",
// Tier 1: Shortcuts & slash commands
shortcuts: [{ key: "Mod-b", run: (editor) => { /* toggle bold */ return true; } }],
slashCommands: [{ id: "heading", title: "Heading", keywords: ["h1"] }],
// Tier 2: AST & widgets
remarkPlugins: [remarkMath],
widgets: [{
nodeType: "code",
match: (node) => node.lang === "mermaid",
render: (node, source) => renderMermaidChart(source),
destroy: (el) => el.remove(),
}],
// Tier 3: Raw CM6
cmExtensions: [myCodeMirrorExtension],
};Build, test, and run the demo
pnpm install
pnpm build # build all packages
pnpm test # run all tests
# Electron demo
pnpm dev:electron-demoWe'd love your help — whether it's a typo fix, a new plugin, or a deep core change. Here's the 5-minute version:
- Fork this repo — click the Fork button at the top of the page.
- Clone your fork locally:
git clone https://github.com//Nexus-Editor.git cd Nexus-Editor pnpm install
3. **Create a branch** following our naming convention (see `CONTRIBUTING.md`):
```bash
git checkout -b feat/<scope>/<short-description>
- Make your change — write tests, run
pnpm test, runpnpm build. - Commit using Conventional Commits:
git commit -m "feat(core): add getSelectedText() API"
6. **Push** to your fork and **open a Pull Request** against `main`.
### Before opening a PR, please read
- [CONTRIBUTING.md](./CONTRIBUTING.md) — branch naming, Conventional Commits scope whitelist, when to file an OpenSpec proposal, test matrix.
- [.github/PULL_REQUEST_TEMPLATE.md](./.github/PULL_REQUEST_TEMPLATE.md) — the PR description template.
- [openspec/AGENTS.md](./openspec/AGENTS.md) — required for new capabilities or breaking API changes.
> 🟢 **Good first issues** are labeled [`good first issue`](https://github.com/floatboatai/Nexus-Editor/labels/good%20first%20issue) — start there if you're new to the codebase.
---
## 📄 License
[MIT](./LICENSE) © floatboat
---
<div align="center">
## ⭐ Like what you see?
**If Nexus-Editor saved you from writing yet another Markdown editor from scratch, the kindest thing you can do is hit the ⭐ button** — it helps other devs find the project, and it genuinely makes a difference.
### Spread the word
- 🐦 **Tweet about it** — tag us, we'll retweet
- 📝 **Blog about your integration** — open a PR to list it in `SHOWCASE.md`
- 💬 **Share in your team's Slack / Discord** — that's how 90% of devs discover tools
- 🐛 **Open an issue** if something feels off — even "this is confusing" is valuable feedback
**Built with ❤️ for makers who still believe Markdown is the right format.**
</div>
## 使用简介
Nexus‑Editor是一款Markdown实时编辑器,可以一边输入一边预览渲染效果。欢迎提交Issue反馈bug与新需求。