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

ape-rich-text-renderer

v0.4.0

Published

Lightweight React renderer for TipTap JSON content. Read-side companion of ape-rich-text-editor.

Readme

ape-rich-text-renderer

Lightweight React renderer for TipTap JSONContent. The read-side companion of ape-rich-text-editor.

  • No TipTap runtime — only the JSONContent type is imported. Apps that just display content do not pay the editor's bundle cost.
  • No Tailwind required at consumer level — styles ship pre-compiled in dist/style.css.
  • Single component, zero config — pass content and you're done.
  • Visual parity with the editor — same heading sizes, list styles, code block rendering. True WYSIWYG.

Install

pnpm add ape-rich-text-renderer
# or
npm install ape-rich-text-renderer
# or
yarn add ape-rich-text-renderer

React 18 or 19 is required (declared as a peer dependency).

Quick start

import { RichTextRenderer, type JSONContent } from 'ape-rich-text-renderer'
import 'ape-rich-text-renderer/style.css'

const content: JSONContent = {
  type: 'doc',
  content: [
    { type: 'heading', attrs: { level: 1 }, content: [{ type: 'text', text: 'Hello' }] },
    { type: 'paragraph', content: [{ type: 'text', text: 'World.' }] },
  ],
}

export function Article() {
  return <RichTextRenderer content={content} />
}

The CSS import is required once per app (typically at your entry point).

Loading saved content

In practice, you load JSONContent from your database or API and pass it to the renderer.

import { useEffect, useState } from 'react'
import { RichTextRenderer, type JSONContent } from 'ape-rich-text-renderer'
import 'ape-rich-text-renderer/style.css'

export function Article({ id }: { id: string }) {
  const [body, setBody] = useState<JSONContent | null>(null)

  useEffect(() => {
    fetch(`/api/articles/${id}`)
      .then(r => r.json())
      .then(article => setBody(article.body))
  }, [id])

  if (!body) return <p>Cargando…</p>

  return (
    <article>
      <RichTextRenderer content={body} />
    </article>
  )
}

If the saved JSON contains nodes the renderer does not recognize (older schema, custom extensions you do not ship), the renderer renders the children when present and ignores the wrapper — your app does not crash on schema drift.

Props

| Prop | Type | Description | | ----------- | ------------- | --------------------------------------------------------------------------------------------------------- | | content | JSONContent | TipTap document JSON (output of editor.getJSON() from the editor package). Required. | | className | string | Optional extra classes for the wrapping <div>. Useful to constrain width or add prose styling on top. |

Supported nodes

doc, heading (levels 1–3), paragraph, text, bulletList, orderedList, listItem, blockquote, codeBlock, hardBreak, horizontalRule, image (with width, alignment, float), table, tableRow, tableHeader, tableCell (with backgroundColor, textAlign, colspan, rowspan).

Supported marks

bold, italic, underline, strike, code, textStyle (color), highlight, link.

Round-trip with the editor

The renderer is the read-only counterpart of ape-rich-text-editor. The flow:

┌──────────────┐   editor.getJSON()   ┌─────────┐   loadFromDB    ┌────────────────┐
│ RichText     │ ───────────────────► │   DB    │ ──────────────► │ RichText       │
│   Editor     │                      │  JSON   │                 │   Renderer     │
└──────────────┘                      └─────────┘                 └────────────────┘

Visual fidelity is guaranteed because both packages share the same heading sizes, list styles, blockquote borders, code block colors, etc. You can edit a document in the editor, save it, render it, and re-edit it without any drift.

Why a separate package?

Splitting editor and renderer is the difference between ~5 KB and ~250 KB minified. Public-facing pages should never bundle a WYSIWYG.

| | Minified | Min + gzip | | ------------------------ | -------- | ---------- | | ape-rich-text-renderer | ~5 KB | ~2 KB | | ape-rich-text-editor | ~250 KB | ~75 KB |

A typical CMS application bundles both:

  • ape-rich-text-editor on the admin/draft pages.
  • ape-rich-text-renderer on the public-facing site.

Tailwind compatibility

The lib does not require the consumer to install Tailwind. Styles ship pre-compiled in dist/style.css.

How isolation works

dist/style.css is post-processed at build time so every rule is scoped under the .ape-rte-renderer wrapper class. Importing the stylesheet anywhere in your app will not touch elements outside the renderer:

  • Tailwind utilities are wrapped in :where(.ape-rte-renderer) — specificity stays at (0,1,0), identical to a bare Tailwind utility. The consumer can override any of them by passing their own className and source order decides the winner.
  • Tailwind v4's engine-variable reset (*, :before, :after, ::backdrop { --tw-…: 0 }) is rewritten to apply only to descendants of .ape-rte-renderer, so the consumer's --tw-* variables stay untouched.
  • The Preflight base reset (margins/font-family on *, h1-h6, a, button, lists) was already removed in 0.2.1 and is not shipped at all.

Tradeoffs to know

A consumer's global utility rule (e.g. .flex { gap: 99px } in their own CSS) will still affect descendants inside the renderer because :where() has specificity 0. If you need absolute isolation from the consumer's own Tailwind utilities, scope them in your app, not globally.

Server-side rendering

The renderer has no client-only code — it is plain JSX over the JSON tree. Safe to use in Next.js Server Components, Astro, Remix, or any SSR framework. No 'use client' directive required.

// Next.js App Router — Server Component
import { RichTextRenderer } from 'ape-rich-text-renderer'
import 'ape-rich-text-renderer/style.css'

export default async function ArticlePage({ params }: { params: { id: string } }) {
  const article = await db.articles.findUnique({ where: { id: params.id } })
  return <RichTextRenderer content={article.body} />
}

Development

pnpm install
pnpm dev          # opens the playground at http://localhost:3334
pnpm build        # builds dist/index.{js,cjs,d.ts} and dist/style.css
pnpm type-check

The dev/ playground renders sample JSONContent covering all supported nodes and marks. Useful to validate visual changes.

Release

Tag-driven release. To publish a new version:

  1. Bump version in package.json.
  2. git commit -am "chore(release): 0.x.y"
  3. git tag v0.x.y && git push --tags

The GitHub Action builds and publishes to npm. Set the NPM_TOKEN repository secret first.

License

UNLICENSED — internal use within APE-SENA-2025.