npm.io
0.23.5 • Published 4d ago

@jackuait/blok

Licence
Apache-2.0
Version
0.23.5
Deps
5
Size
74.7 MB
Vulns
0
Weekly
1.5K

Blok logotype

It's Blok!

Blok is a headless, block-based rich text editor for the web. If you've used Notion, you know the feel: every paragraph, heading, image, or list is its own block that you can drag around, nest, and convert into something else.

The difference from a normal contenteditable setup is the data. A contenteditable field hands you one HTML blob and leaves you to parse it. Blok stores content as typed JSON blocks instead, so the output is the same whether you save it to a database, diff it, or render it on a server that never touches the DOM.

It's headless on purpose. Blok ships the editing engine and a set of tools; it does not impose a chrome or a theme. You wire it into your own UI.

What's in the box

Feature What you get
Block tools Paragraph, heading, list, quote, callout, code, image, divider, table, toggle, and a column layout. Plus a Notion-style database block (rows are child blocks) and embed/bookmark blocks for pasted links.
Inline formatting Bold, italic, underline, strikethrough, inline code, link, and a highlight marker.
Slash menu & markdown Type / in an empty block to search and insert, or type markdown (#, -, 1., [], >) and it converts on space.
Drag and drop Pointer-based reordering (not the flaky HTML5 drag API). Grab multiple blocks, hold Alt to duplicate while dragging, auto-scrolls near edges. Keyboard works too.
Undo/redo on Yjs History is CRDT-backed: undo restores the caret, groups small edits, and batches atomically via blocks.transact().
68 locales, RTL Reads the browser language, lazy-loads the matching locale, and lays out right-to-left scripts correctly.
Plugin system Three extension points — block tools, inline tools, block tunes — with lifecycle hooks, paste handling, and conversion rules. Tools reach the editor through 18 API namespaces (blocks, caret, selection, …).
Smart paste A handler chain keeps block structure intact on internal paste, strips Google Docs HTML noise, and lets tools claim specific file types or patterns.
Block conversion Turn one block type into another from the inline toolbar or in code, one block or a whole selection at a time.
Read-only mode Call readOnly.set(true) and the editor re-renders without editing affordances.
Accessibility ARIA live announcements for drag and block ops, Notion-style vertical caret movement, semantic data attributes for tests.

Installation

With a bundler (Vite, webpack, Rollup, etc.):

npm install @jackuait/blok
# or: yarn add @jackuait/blok / pnpm add @jackuait/blok
// ESM
import Blok from '@jackuait/blok';

// CommonJS
const { Blok } = require('@jackuait/blok');

The core package ships the engine but no tools, so you choose what to load. Import individual tools from @jackuait/blok/tools, or grab the batteries-included bundle:

import { Blok, defaultTools, defaultInlineTools } from '@jackuait/blok/full';

new Blok({
  holder: 'editor',
  tools: defaultTools,
  inlineTools: defaultInlineTools,
});
Other entry points
  • @jackuait/blok/react — React 18/19 adapter. The recommended entry point is <BlokEditor>, an all-in-one component that forwards a ref to the live Blok instance:

    const [data, setData] = useState(initialData);
    <BlokEditor tools={tools} data={data} onSave={setData} theme={theme} />;

    data + onSave make <BlokEditor> a true controlled component. data is reactive: passing new content re-renders the editor in place (deep-equal–deduped, so identical content never clobbers the caret). onSave is the output half: it fires — debounced — with the full serialized OutputData on every content change, so you no longer poll ref.current.save() by hand. Wiring onSave={setData} is safe and caret-stable: the adapter records the editor's own emitted output as the content baseline, so echoing it back deep-equal–dedupes to a no-op (no re-render) while genuine external data changes still render. (You can still forward a ref and call ref.current.render(newData) for ad-hoc reloads, or use the lower-level onChange(api, event) for mutation events.)

    Reactive props (readOnly, theme, width, autofocus) sync without remounting. When structural config like tools needs to change, pass a deps array — the editor is destroyed and recreated whenever any dep value changes. Keep each value inside deps referentially stable: pass primitives or useMemo-stable objects, since a dep value whose identity changes every render recreates the editor each time. (The individual values are compared, not the array wrapper, so a fresh [a, b] literal each render is fine when a and b are stable; omitting deps creates the editor once.)

    Don't wrap <BlokEditor> in styled() or any HOC that reserves the theme prop — styled-components claims theme for its own ThemeProvider, so it never reaches the editor and theme sync silently breaks. Render <BlokEditor> directly and style it through className.

    For advanced control (e.g., rendering outside a single container), use useBlok + BlokContent directly.

  • @jackuait/blok/markdownmarkdownToBlocks(md) to import Markdown (GFM, with optional math) as Blok data.

  • @jackuait/blok/locales — locale data, if you'd rather load it yourself.

CDN (no bundler)
<script src="https://unpkg.com/@jackuait/blok/dist/blok.iife.js"></script>
<!-- or jsDelivr: https://cdn.jsdelivr.net/npm/@jackuait/blok/dist/blok.iife.js -->

<script>
  const editor = new BlokEditor.Blok({ holder: 'editor' });
</script>

The IIFE build puts everything under the BlokEditor global.

Documentation

Full docs live at blokeditor.com: API reference, an interactive demo, usage guides, and a migration guide if you're coming from Editor.js.

Community

There's a Telegram channel at t.me/that_ai_guy for updates and questions about Blok and related projects.

License & Attribution

Blok is licensed under the Apache License 2.0. See NOTICE for attribution.

Blok was forked from Editor.js by CodeX in November 2025 and reworked heavily since. The original Editor.js code remains CodeX under Apache-2.0; Blok-specific changes are JackUait, also under Apache-2.0.

Keywords