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

@b10cks/richtext

v0.4.0

Published

Framework-agnostic rich text rendering for b10cks Rich text

Readme

@b10cks/richtext

Framework-agnostic rich text rendering for b10cks, the open-source headless CMS.

Converts the ProseMirror JSON documents produced by the b10cks editor into HTML or plain text — with zero dependencies, full SSR support, and a tiny bundle (5.5 kB ESM · 1.8 kB gzip · 1.6 kB Brotli).

Used internally by the b10cks framework integrations:

  • @b10cks/react · @b10cks/vue · @b10cks/svelte · @b10cks/next · @b10cks/nuxt

Installation

npm install @b10cks/richtext

No peer dependencies required.

Quick start

import { renderRichText } from '@b10cks/richtext'

const html = renderRichText(document)

document is the JSON value stored by b10cks for a rich text field. null and undefined are accepted and render as an empty string.

HTML rendering

renderRichText(document, options?) · renderRichTextHtml

import { renderRichText } from '@b10cks/richtext'

const html = renderRichText(document, {
  internalLinkHandler: (attrs) => `/blog/${attrs.content}`,
  placeholderHandler:  (key)   => values[key] ?? null,
})

createRichTextRenderer(options?) · createRichTextHtmlRenderer

Creates a reusable renderer — useful when options are constant across many documents:

import { createRichTextRenderer } from '@b10cks/richtext'

const renderer = createRichTextRenderer({
  internalLinkHandler: (attrs) => `/blog/${attrs.content}`,
})

const html = renderer.render(document)

Plain text rendering

Strips all markup. Useful for search indexing, meta descriptions, and Open Graph previews.

renderRichTextAsText(document, options?)

import { renderRichTextAsText } from '@b10cks/richtext'

const text = renderRichTextAsText(document)

// Custom block separator (default: '\n\n')
const oneLiner = renderRichTextAsText(document, { blockSeparator: ' ' })

createRichTextTextRenderer(options?)

import { createRichTextTextRenderer } from '@b10cks/richtext'

const renderer = createRichTextTextRenderer({ blockSeparator: ' ' })
const text = renderer.render(document)

Internal links

The b10cks editor stores internal links as marks with a content ID and an optional anchor:

{
  "type": "internalLink",
  "attrs": {
    "content": "01ksarpy7hd99pwbfe26rc04jb",
    "anchor": null
  }
}

Without a handler the link renders with href="#". Pass internalLinkHandler to resolve the ID to a real URL:

renderRichText(document, {
  internalLinkHandler: (attrs) => {
    // attrs.content — the content record ID
    // attrs.anchor  — optional anchor fragment
    const slug = slugMap[attrs.content ?? '']
    return slug ? `/${slug}${attrs.anchor ? `#${attrs.anchor}` : ''}` : null
  },
})

Returning null or undefined falls back to href="#".

The rendered element carries both data-type="internal" (matching the CMS output) and data-b10cks-internal-link so client-side router handlers can target either attribute.

Placeholder tokens

The b10cks editor supports inline placeholder tokens — variables like {companyName} that are stored as atomic nodes:

{ "type": "placeholderToken", "attrs": { "key": "companyName", "label": "{companyName}" } }

Pass placeholderHandler to substitute real values at render time:

const values = { companyName: 'Google Inc', productName: 'Workspace' }

renderRichText(document, {
  placeholderHandler: (key, label) => values[key] ?? null,
})
// → "Welcome to Google Inc" instead of "Welcome to {companyName}"

The handler receives:

  • key — the variable name (e.g. "companyName")
  • label — the display hint shown in the editor (e.g. "{companyName}")

Returning null or undefined leaves the token as a <span data-type="placeholder-token" data-key="…" data-label="…"> so it can be replaced client-side instead. This works identically in renderRichTextAsText — resolved values are injected as plain text, unresolved tokens emit nothing.

Supported node and mark types

| Node | HTML output | |---|---| | paragraph | <p> | | heading | <h1><h6> | | blockquote | <blockquote> | | codeBlock | <pre><code> | | bulletList | <ul> | | orderedList | <ol> | | listItem | <li> | | hardBreak | <br> | | horizontalRule | <hr> | | image | <img> | | table / tableRow / tableHeader / tableCell | <table> / <tr> / <th> / <td> | | placeholderToken | resolved value or <span data-type="placeholder-token"> |

| Mark | HTML output | |---|---| | bold | <strong> | | italic | <em> | | strike | <s> | | underline | <u> | | code | <code> | | link | <a href="…"> | | internalLink | <a href="…" data-type="internal" data-b10cks-internal-link> | | textClass | <span class="…"> |

Types

import type {
  RichTextDocument,
  RichTextHtmlOptions,
  RichTextTextOptions,
  RichTextInternalLinkAttrs,
  RichTextInternalLinkHandler,
  RichTextPlaceholderHandler,
  RichTextRenderer,
  RichTextTextRenderer,
} from '@b10cks/richtext'

Framework components

For a framework-specific component that handles the HTML rendering for you, use the matching wrapper package:

License

MIT