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

@cosmicjs/rich-text

v0.2.0

Published

Official renderer for Cosmic rich-text (markdown + shortcode blocks and inline object embeds): React components plus a framework-agnostic HTML string renderer.

Readme

@cosmicjs/rich-text

Official renderer for Cosmic rich-text metafields. Rich-text values are stored as markdown prose interleaved with {{shortcode}} block tokens. Each block is either a reusable snippet defined in your bucket settings (synced) or an editable per-instance copy. This package parses the value, resolves blocks against their definitions, and renders to React with an overridable component per block, or to a plain HTML string via the React-free @cosmicjs/rich-text/html entry point.

Install

npm install @cosmicjs/rich-text

react is a peer dependency.

Usage

Pass the bucket's block definitions (settings.content_blocks) so {{name}} tokens can be expanded.

import { RichText } from '@cosmicjs/rich-text';

export default function Post({ post, blocks }) {
  return <RichText value={post.metadata.content} blocks={blocks} />;
}

Overriding block rendering

By default each block renders as a data-block div wrapping its content. Provide a components map keyed by block name to customize rendering.

import { RichText, BlockProps } from '@cosmicjs/rich-text';

const Callout = ({ contentHtml }: BlockProps) => (
  <aside
    className="my-callout"
    dangerouslySetInnerHTML={{ __html: contentHtml }}
  />
);

<RichText value={value} blocks={blocks} components={{ callout: Callout }} />;

Each component receives { name, definition, contentHtml }, where contentHtml is the block's content already rendered to HTML: the inline content for an editable instance, or the definition's content for a synced reference.

Inline object embeds

A rich-text value can also reference a live Cosmic object inline with the reserved {{ object ... /}} token (distinct from a block: the content lives in the referenced object, not in bucket settings):

{{ object type="posts" id="64f0...abc" slug="hello-world" /}}

Render embeds by providing an objects component map (keyed by object type slug) and a resolveObject function. Fetch the parent object with relationship depth so the referenced objects are available, then resolve by id:

import { RichText, ObjectBlockProps } from '@cosmicjs/rich-text';

const PostCard = ({ object }: ObjectBlockProps) =>
  object ? <a href={`/posts/${object.slug}`}>{object.title}</a> : null;

const related = post.metadata?.related ?? [];
const byId = new Map(related.map((o) => [o.id, o]));

<RichText
  value={value}
  blocks={blocks}
  objects={{ posts: PostCard }}
  resolveObject={({ id }) => byId.get(id)}
/>;

Each object component receives { id, type, slug, object }. When no component is registered for a type, a default placeholder renders (the reference is never silently dropped).

Imperative API

import { renderRichText } from '@cosmicjs/rich-text';

const nodes = renderRichText(value, { blocks });

Render to an HTML string (no React)

For non-React stacks (Vue, Svelte, Astro, server templates), import renderToHtml from the @cosmicjs/rich-text/html entry point, which has no React dependency. It returns a single HTML string.

import { renderToHtml } from '@cosmicjs/rich-text/html';

const html = renderToHtml(value, {
  blocks,
  // Optional: customize block markup.
  blockWrapper: ({ name, innerHtml }) =>
    `<aside class="block block-${name}">${innerHtml}</aside>`,
  // Optional: resolve inline object embeds to your own HTML.
  resolveObjectHtml: ({ id }) => byId.get(id)?.html,
});

By default blocks render to the same data-block wrapper as the React renderer, and unresolved object embeds render to a data-object placeholder.

Block definitions

A block definition has this shape (stored in settings.content_blocks):

interface BlockDefinition {
  name: string; // shortcode, e.g. "callout"
  title?: string;
  description?: string;
  content: string; // markdown, plain text, or raw HTML
  editor: 'rich-text' | 'plain' | 'html';
}

Shortcode grammar

{{ name /}}                                      synced block reference
{{ name }}...{{/ name }}                          editable ("Edit on page") instance
{{ object type="posts" id="..." slug="..." /}}   inline object embed

A synced reference ({{ name /}}) resolves its content from the block definition, so editing the saved block updates every synced instance. An editable instance ({{ name }}...{{/ name }}) stores its content inline, so it is unique to that value and no longer tracks the saved block. Unknown blocks (no matching definition) are dropped unless keepUnknown is set. The object (and objects) names are reserved for inline object embeds.

Fetching block definitions

Rich-text values are served verbatim (markdown + {{shortcode}} tokens); the API never pre-renders them. Fetch the bucket's block definitions once and reuse them across objects. The easiest way is the official SDK:

import { createBucketClient } from '@cosmicjs/sdk';

const cosmic = createBucketClient({ bucketSlug, readKey });
const { blocks } = await cosmic.blocks.find();

Or call the endpoint directly:

GET buckets/{slug}/blocks   ->   { "blocks": [ ...BlockDefinition ] }

The endpoint is read-key authed and Fastly-cached on the bucket. The same data is also available on the bucket object at settings.content_blocks. Pass the result as the blocks prop above.