npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@jackuait/blok

v0.24.2

Published

Blok — headless, highly extensible rich text editor built for developers who need to implement a block-based editing experience (similar to Notion) without building it from scratch

Downloads

3,529

Readme

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.