Open source · Plugin-based · TypeScript first

Production-ready
rich text editor
for React

Inkstream is a modular ProseMirror-based editor SDK. Add only the plugins you need, extend with custom ones, and ship with confidence.

20+Plugins
700+Test coverage
MITLicense

Try it live

A fully interactive editor running right here in the browser. Format text, add links, create lists — everything works.

inkstream.dev/demo
Loading editor…

Built with @inkstream/react-editor

Everything you need

From simple text formatting to advanced Pro features — Inkstream has it covered.

🧩

Plugin Architecture

Built with modularity in mind. Import only what you need — bold, tables, AI assistant — or build your own plugin in minutes.

700+ tests
🚀

Production Ready

Battle-tested with 700+ Jest tests. Comprehensive coverage across all plugins, commands, and edge cases.

🔷

TypeScript First

Fully typed API with strict mode. Your IDE understands your editor — autocomplete, type errors, the works.

Pro
📄

Markdown Export

Export content to Markdown. Import from Markdown. Perfect for documentation, note-taking, and CMS integrations.

Free & Pro Tiers

Core formatting features free forever. Advanced plugins — tables, AI assistant, collaboration — available as Pro add-ons.

🛠️

Fully Extensible

Create custom plugins, commands, toolbar items, and UI components. Full control over editor schema and behavior.

MyEditor.tsx
import { RichTextEditor } from '@inkstream/react-editor'
import { availablePlugins } from '@inkstream/starter-kit'
import { headingPlugin } from '@inkstream/heading'
const PLUGINS = [headingPlugin, availablePlugins.bold, availablePlugins.italic, availablePlugins.history]
export default function MyEditor() {
return (
<RichTextEditor
plugins={PLUGINS}
toolbarLayout={['heading'heading, '|'|, 'bold'bold, 'italic'italic, '|'|, 'undo'undo, 'redo'redo]}
onChange={(html) => console.log(html)}
/>
)
}

Built for Developers

Simple API. Powerful features. Minimal setup. Get a production-ready editor running in under 5 minutes.

  • 📦Import only what you need
  • 🔷TypeScript support out of the box
  • 🛠️Fully customisable toolbar
  • 🧩Plugin-based architecture
  • ♾️Custom plugins in minutes
✨ v0.1.10+

Theming & Dark Mode

The editor ships with a full CSS custom-properties theming system. Auto-detects the user's OS colour scheme out of the box — or take full control with props and token overrides.

🖥Default

Auto mode

Follows the user's OS preference via `prefers-color-scheme`. No code needed.

theme="light"

Light mode

Forces the light palette regardless of the OS setting.

🌙theme="dark"

Dark mode

Forces the dark palette regardless of the OS setting.

Choose your integration style

Add `showThemeToggle` to render a Auto / Light / Dark switcher button at the right end of the toolbar. Zero extra wiring required — the editor manages its own theme state.

Available CSS tokens
--ink-bgEditor background
--ink-surfaceToolbar background
--ink-accentBrand / active colour
--ink-textPrimary text
--ink-text-mutedSecondary text
--ink-borderBorder colour
--ink-radius-mdBorder radius
--ink-shadow-mdDropdown shadow
+ 11 more — see package README for full list
MyEditor.tsx
import { RichTextEditor } from '@inkstream/react-editor'
export default function MyEditor() {
return (
<RichTextEditor
initialContent="<p>Hello, world!</p>"
showThemeToggle // adds Auto/Light/Dark button to toolbar
/>
)
}
💡

Try the theme toggle in the live demo above

The Try it live section uses showThemeToggle. Look for the monitor icon (🖥) at the right end of the toolbar to switch between Auto, Light, and Dark right now.

Get started in minutes

One install, zero configuration. Add plugins as you need them.

Terminal
$ npm install @inkstream/react-editor @inkstream/editor-core
App.tsx
'use client'
import { RichTextEditor } from '@inkstream/react-editor'
import { availablePlugins } from '@inkstream/starter-kit'
function App() {
return (
<RichTextEditor
plugins={[
availablePlugins.bold,
availablePlugins.italic,
availablePlugins.underline
]}
toolbarLayout={['bold', 'italic', 'underline']}
initialContent={'<p>Hello, Inkstream!</p>'}
/>
)
}