Skip to content

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

License

Notifications You must be signed in to change notification settings

Labbs/openblock

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, documented
editor.pm.view           // EditorView
editor.pm.state          // EditorState
editor.pm.dispatch(tr)   // Dispatch transactions
editor.pm.setNodeAttrs(pos, attrs)

// ❌ Other editors - hacky, undocumented
(editor as any).prosemirrorView
(editor as any)._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!

function Editor() {
  const editor = useOpenBlock({
    initialContent: [
      {
        id: '1',
        type: 'paragraph',
        props: {},
        content: [{ type: 'text', text: 'Hello, World!', styles: {} }]
      }
    ],
  });

  return (
    <>
      <OpenBlockView editor={editor} />
      <SlashMenu editor={editor} />
      <BubbleMenu editor={editor} />
      <TableHandles editor={editor} />
    </>
  );
}

Vanilla JS

import { OpenBlockEditor } from '@labbs/openblock-core';
// CSS is auto-injected by default - no import needed!

const editor = new OpenBlockEditor({
  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 blocks
editor.setDocument(blocks)              // Replace document
editor.getBlock(id)                     // Find block by ID
editor.insertBlocks(blocks, ref, pos)   // Insert blocks
editor.updateBlock(id, update)          // Update block
editor.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 table
if (isInTable(editor.pm.state)) {
  // Add row after current row
  addRowAfter(editor.pm.state, editor.pm.view.dispatch);

  // Add column before current column
  addColumnBefore(editor.pm.state, editor.pm.view.dispatch);

  // Delete current row
  deleteRow(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              // EditorView
editor.pm.state             // EditorState
editor.pm.doc               // Document
editor.pm.dispatch(tr)      // Dispatch transaction
editor.pm.setNodeAttrs(pos, attrs)

Block Format

interface Block {
  id: string;
  type: string;
  props: Record<string, unknown>;
  content?: InlineContent[];
  children?: Block[];
}

// Example document
const blocks = [
  {
    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
<TableHandles editor={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

Documentation

Guide Description
React Integration Hooks, components, and patterns for React
Custom Blocks Creating your own block types
Custom Marks Creating inline formatting marks
Plugins Building ProseMirror plugins
Styling CSS customization and theming

Packages

Package Description
@labbs/openblock-core Framework-agnostic editor core
@labbs/openblock-react React 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

License

Stars

Watchers

Forks

Packages