Skip to content

Repository files navigation

OpenBlock

A fully open-source block editor with public ProseMirror API

FeaturesQuick StartAPIDocsLive Demo


Why OpenBlock?

Unlike other editors (BlockNote, Tiptap), OpenBlock exposes all ProseMirror internals through a typed, documented API. No more hacks.

// ✅ OpenBlock - clean, typed, documentededitor.pm.view// EditorVieweditor.pm.state// EditorStateeditor.pm.dispatch(tr)// Dispatch transactionseditor.pm.setNodeAttrs(pos,attrs)// ❌ Other editors - hacky, undocumented(editorasany).prosemirrorView(editorasany)._tiptapEditor.view

Features

  • Public ProseMirror API — Full access via editor.pm.*
  • Block-based JSON — Notion-like format, easy to store and transform
  • Framework-agnostic — Vanilla JS core with React bindings (Vue, Svelte coming)
  • TypeScript first — Full type safety throughout
  • Rich block types — Headings, lists, code blocks, tables, columns, and more
  • Built-in UI — Slash menu, bubble menu, drag & drop, table handles

Quick Start

Installation

First, configure npm to use GitHub Packages for the @labbs scope. Create or edit .npmrc in your project:

@labbs:registry=https://npm.pkg.github.com

Then install the packages:

npm install @labbs/openblock-core @labbs/openblock-react

React

import{useOpenBlock,OpenBlockView,SlashMenu,BubbleMenu,TableHandles}from'@labbs/openblock-react';// CSS is auto-injected by default - no import needed!functionEditor(){consteditor=useOpenBlock({initialContent: [{id: '1',type: 'paragraph',props: {},content: [{type: 'text',text: 'Hello, World!',styles: {}}]}],});return(<><OpenBlockVieweditor={editor}/><SlashMenueditor={editor}/><BubbleMenueditor={editor}/><TableHandleseditor={editor}/></>);}

Vanilla JS

import{OpenBlockEditor}from'@labbs/openblock-core';// CSS is auto-injected by default - no import needed!consteditor=newOpenBlockEditor({initialContent: [/* blocks */],});editor.mount(document.getElementById('editor'));

Note: CSS styles are automatically injected into the document head. To disable auto-injection and provide your own styles, set injectStyles: false in the editor config.

API

Document Operations

editor.getDocument()// Get all blockseditor.setDocument(blocks)// Replace documenteditor.getBlock(id)// Find block by IDeditor.insertBlocks(blocks,ref,pos)// Insert blockseditor.updateBlock(id,update)// Update blockeditor.removeBlocks(ids)// Delete blocks

Text Formatting

editor.toggleBold()editor.toggleItalic()editor.toggleUnderline()editor.toggleStrikethrough()editor.toggleCode()editor.setTextColor(color)editor.setBackgroundColor(color)

Block Types

editor.setBlockType('heading',{level: 1})editor.setBlockType('codeBlock',{language: 'typescript'})editor.setBlockType('bulletList')editor.setBlockType('orderedList')editor.setBlockType('blockquote')editor.setBlockType('table')

Table Commands

import{addRowAfter,addRowBefore,deleteRow,addColumnAfter,addColumnBefore,deleteColumn,goToNextCell,goToPreviousCell,isInTable}from'@labbs/openblock-core';// Check if cursor is in a tableif(isInTable(editor.pm.state)){// Add row after current rowaddRowAfter(editor.pm.state,editor.pm.view.dispatch);// Add column before current columnaddColumnBefore(editor.pm.state,editor.pm.view.dispatch);// Delete current rowdeleteRow(editor.pm.state,editor.pm.view.dispatch);}// Navigate between cells (Tab / Shift+Tab)goToNextCell(editor.pm.state,editor.pm.view.dispatch);goToPreviousCell(editor.pm.state,editor.pm.view.dispatch);

ProseMirror Access

editor.pm.view// EditorVieweditor.pm.state// EditorStateeditor.pm.doc// Documenteditor.pm.dispatch(tr)// Dispatch transactioneditor.pm.setNodeAttrs(pos,attrs)

Block Format

interfaceBlock{id: string;type: string;props: Record<string,unknown>;content?: InlineContent[];children?: Block[];}// Example documentconstblocks=[{id: 'heading-1',type: 'heading',props: {level: 1},content: [{type: 'text',text: 'Welcome',styles: {bold: true}}]},{id: 'para-1',type: 'paragraph',props: {},content: [{type: 'text',text: 'Hello world',styles: {}}]},{id: 'table-1',type: 'table',props: {},children: [{id: 'row-1',type: 'tableRow',props: {},children: [{id: 'header-1',type: 'tableHeader',props: {},content: [{type: 'text',text: 'Name',styles: {}}]},{id: 'header-2',type: 'tableHeader',props: {},content: [{type: 'text',text: 'Value',styles: {}}]}]},{id: 'row-2',type: 'tableRow',props: {},children: [{id: 'cell-1',type: 'tableCell',props: {},content: [{type: 'text',text: 'Item',styles: {}}]},{id: 'cell-2',type: 'tableCell',props: {},content: [{type: 'text',text: '100',styles: {}}]}]}]}];

React Components

OpenBlockView

The main editor component that renders the ProseMirror view.

SlashMenu

Displays a command palette when typing / to insert blocks.

BubbleMenu

Floating toolbar that appears when selecting text for formatting.

TableHandles

Renders handles on tables for adding/removing rows and columns.

import{TableHandles}from'@labbs/openblock-react';// Add to your editor<TableHandleseditor={editor}/>

When hovering over a table:

  • Row handles appear on the left — click to insert/delete rows
  • Column handles appear on top — click to insert/delete columns
  • Extend buttons appear on the right and bottom — click to add rows/columns

Custom Blocks

Create custom React blocks with createReactBlockSpec:

import{createReactBlockSpec,useOpenBlock,SlashMenu,useCustomSlashMenuItems}from'@labbs/openblock-react';// Define a custom blockconstAlertBlock=createReactBlockSpec({type: 'alert',propSchema: {alertType: {default: 'info'},message: {default: ''},},content: 'none',},{render: ({ block })=>(<divclassName={`alert alert-${block.props.alertType}`}>{block.props.message}</div>),slashMenu: {title: 'Alert',description: 'Insert an alert box',aliases: ['warning','info'],group: 'Basic',},});// Use custom blocksconstCUSTOM_BLOCKS=[AlertBlock];functionEditor(){consteditor=useOpenBlock({customBlocks: CUSTOM_BLOCKS});constcustomItems=useCustomSlashMenuItems(editor,CUSTOM_BLOCKS);return(<><OpenBlockVieweditor={editor}/><SlashMenueditor={editor}additionalItems={customItems}/></>);}

See Custom Blocks Guide for more details.

Documentation

GuideDescription
React IntegrationHooks, components, and patterns for React
Custom BlocksCreating your own block types
Custom MarksCreating inline formatting marks
PluginsBuilding ProseMirror plugins
StylingCSS customization and theming

Packages

PackageDescription
@labbs/openblock-coreFramework-agnostic editor core
@labbs/openblock-reactReact bindings and components

Development

# Install dependencies
pnpm install
# Build all packages
pnpm build
# Run example in dev mode
pnpm dev

License

Apache-2.0

About

Open-source block editor with public ProseMirror API. Full access to editor.pm.view, editor.pm.state, and all internals. No hacks needed.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages