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

@scrider/formatter

v1.8.0

Published

Delta converters and block handlers for rich-text content

Readme

@scrider/formatter

Schema, conversion and block handlers for rich-text content. HTML, Markdown, sanitization.

Overview

@scrider/formatter is the processing layer of the Scrider ecosystem. It provides format definitions (schema), HTML/Markdown conversion, sanitization, and extensible block handlers — all as pure, stateless functions on top of @scrider/delta. Strict TypeScript, zero runtime dependencies beyond @scrider/delta.

Key Features

  • Schema — extensible format registry (32 built-in formats: inline, block, embed — including softBreak for Shift+Enter line breaks)
  • HTML conversiondeltaToHtml() / htmlToDelta() with DOM adapters (browser + Node.js)
  • Markdown conversiondeltaToMarkdown() / markdownToDelta() (GFM, math, footnotes)
  • Block handlers — tables, footnotes, alerts, columns, inline-box
  • SanitizationsanitizeDelta(), validateDelta(), normalizeDelta()
  • Dual format — ESM + CJS builds
  • Strict TypeScript — full type safety, discriminated unions
  • Stateless — pure functions, no DOM coupling, works in browser, Node.js, Web Workers

Installation

npm install @scrider/formatter @scrider/delta
# or
pnpm add @scrider/formatter @scrider/delta

Optional peer dependencies (install only what you need):

# Node.js HTML conversion (server-side)
pnpm add jsdom

# Markdown conversion
pnpm add unified remark-parse remark-stringify remark-gfm

# Math in Markdown
pnpm add remark-math

Quick Start

import { Delta } from '@scrider/formatter';
import { deltaToHtml, htmlToDelta, createDefaultRegistry } from '@scrider/formatter';

// Create a document
const doc = new Delta()
  .insert('Hello', { bold: true })
  .insert(' world\n');

// Convert to HTML
const registry = createDefaultRegistry();
const html = deltaToHtml(doc, { registry });
// → '<p><strong>Hello</strong> world</p>'

// Convert back to Delta
const delta = htmlToDelta(html, { registry });

API

Schema

import { Registry, createDefaultRegistry, BlockHandlerRegistry } from '@scrider/formatter';

const registry = createDefaultRegistry();  // 32 built-in formats

HTML Conversion

import { deltaToHtml, htmlToDelta } from '@scrider/formatter';

deltaToHtml(delta, { registry })           // Delta → HTML string
htmlToDelta(html, { registry })            // HTML string → Delta

Simple Table presentation (v1.3.4+) — inline borders/shades for clipboard and Office paste (Delta structure unchanged):

import { deltaToHtml, type TablePresentation } from '@scrider/formatter';

const tablePresentation: TablePresentation = {
  grid: true,
  borderColor: '#e7e7e7',
  headerBold: true,
  headerCenter: true,
};

deltaToHtml(delta, { tablePresentation });

See scrider-editor docs/simple-tables.md §8 for the full contract (grid / line, headerShade, zebraRows, defaultCellAlign, …).

Markdown Conversion

import { deltaToMarkdown, markdownToDelta } from '@scrider/formatter';

deltaToMarkdown(delta, options?)           // Delta → Markdown string
await markdownToDelta(markdown, options?)  // Markdown string → Delta (async)

Soft Line Break (softBreak embed)

A Shift+Enter style line break that does not split the containing block. Stored in Delta as { insert: { softBreak: true } } and round-tripped consistently across all three layers:

| Direction | Encoding | |-----------|----------| | HTML | <br data-scrider-embed> (the marker disambiguates it from the <br> placeholder inside an empty paragraph) | | Markdown | " \n" by default — GFM hard break; switch to inline <br> via deltaToMarkdown(delta, { softBreakStyle: 'html' }) |

htmlToDelta also recognises bare <br> between content (e.g. <p>foo<br>bar</p>) as a soft break, while keeping the leading / placeholder shapes (<p><br></p>, <p><br>foo</p>) as regular newlines for backward compatibility. The explicit data-scrider-embed marker overrides the placeholder heuristic, so a lone <br data-scrider-embed> inside an otherwise empty <p> is still parsed as a { softBreak: true } embed (since v1.3.1).

import { Delta, deltaToHtml, deltaToMarkdown } from '@scrider/formatter';

const doc = new Delta()
  .insert('hello')
  .insert({ softBreak: true })
  .insert('world\n');

deltaToHtml(doc);
// → '<p>hello<br data-scrider-embed>world</p>'

deltaToMarkdown(doc);
// → 'hello  \nworld'

deltaToMarkdown(doc, { softBreakStyle: 'html' });
// → 'hello<br>world'

Sanitization

import { sanitizeDelta, validateDelta, normalizeDelta } from '@scrider/formatter';

sanitizeDelta(delta, { registry })         // Remove unknown formats
validateDelta(delta, { registry })         // Check validity (boolean)
normalizeDelta(delta)                      // Normalize operations

Block Handlers

Block handlers process complex block embeds (tables, alerts, footnotes, etc.) stored in Delta as { insert: { block: { type, ... } } }. Pass them to conversion functions via createDefaultBlockHandlers() or register individually:

import {
  createDefaultBlockHandlers,
  deltaToHtml,
  htmlToDelta,
  createDefaultRegistry,
} from '@scrider/formatter';

const registry = createDefaultRegistry();
const blockHandlers = createDefaultBlockHandlers();

// Delta with an alert block → HTML
const html = deltaToHtml(delta, { registry, blockHandlers });
// → '<div class="markdown-alert markdown-alert-note">...</div>'

// HTML with block embeds → Delta
const delta = htmlToDelta(html, { registry, blockHandlers });

Built-in handlers:

| Handler | Block type | Description | |---------|-----------|-------------| | tableBlockHandler | table | Extended tables with colspan/rowspan, nested Delta cells | | alertBlockHandler | alert | GitHub-style alerts ([!NOTE], [!TIP], [!WARNING], etc.) | | footnotesBlockHandler | footnotes | Footnotes with [^id] references | | columnsBlockHandler | columns | Multi-column layout (CSS Grid) | | boxBlockHandler | box | Inline-box with float/overflow |

Ecosystem

@scrider/delta          Core — Delta, OT (0 deps)
    ↑
@scrider/formatter      ← you are here (Schema + Conversion)
    ↑
@scrider/editor         React WYSIWYG Component (planned)

License

MIT