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

kyro-rich-text-react

v0.12.3

Published

React renderer for Kyro CMS Tiptap rich text content

Readme

kyro-rich-text-react

A lightweight, headless React renderer for Kyro CMS rich text content.

When you use the richText field in Kyro CMS, it stores the content as structured Tiptap/ProseMirror JSON (not raw HTML). This package allows you to easily render that JSON structure into React components.

By default, it is completely headless and unstyled, outputting clean semantic HTML (<p>, <h1>, <strong>). You have full control over the rendering by passing in custom components.


Installation

npm install kyro-rich-text-react
# or
pnpm add kyro-rich-text-react
# or
yarn add kyro-rich-text-react

Quick Start

Import the KyroRichTextRenderer component and pass the JSON array from your Kyro API to the content prop.

import React from 'react';
import { KyroRichTextRenderer } from 'kyro-rich-text-react';

export default function BlogPost({ post }) {
  // post.content is the JSON array from Kyro
  return (
    <article className="blog-content">
      <KyroRichTextRenderer content={post.content} />
    </article>
  );
}

Customizing Components (Advanced)

Because the renderer is headless, it doesn't come with CSS classes. If you use a CSS framework like Tailwind, or if you simply want to use your own custom React components for specific nodes (like links or headings), use the components prop.

The components prop accepts an object with two keys:

  • types: For block-level nodes (paragraphs, headings, blockquotes, images)
  • marks: For inline text formatting (bold, italic, links)

Example: Tailwind CSS & Custom Components

import React from 'react';
import { KyroRichTextRenderer, KyroRichTextComponents } from 'kyro-rich-text-react';
import Link from 'next/link';

const customComponents: KyroRichTextComponents = {
  types: {
    // Override headings to include Tailwind classes
    heading: ({ node, children }) => {
      const level = node.attrs?.level || 1;
      const classes = {
        1: 'text-4xl font-extrabold mb-6 mt-8',
        2: 'text-2xl font-bold mb-4 mt-6',
        3: 'text-xl font-semibold mb-3 mt-4',
      };
      const Tag = `h${level}` as keyof JSX.IntrinsicElements;
      
      return <Tag className={classes[level] || ''}>{children}</Tag>;
    },
    
    // Custom Paragraphs
    paragraph: ({ children }) => (
      <p className="text-gray-700 leading-relaxed mb-4">{children}</p>
    ),

    // Render Kyro uploads as responsive images
    image: ({ node }) => (
      <img 
        src={node.attrs?.src} 
        alt={node.attrs?.alt || 'Image'} 
        className="w-full rounded-xl shadow-lg my-6"
      />
    ),
  },
  
  marks: {
    // Map links to Next.js Link component for internal routing
    link: ({ mark, children }) => {
      const href = mark.attrs?.href || '#';
      const isInternal = href.startsWith('/') || href.startsWith('#');

      if (isInternal) {
        return <Link href={href} className="text-blue-600 hover:underline">{children}</Link>;
      }

      // External link
      return (
        <a href={href} target="_blank" rel="noopener noreferrer" className="text-blue-600 hover:underline">
          {children}
        </a>
      );
    },
    
    // Style bold text
    bold: ({ children }) => <strong className="font-bold text-gray-900">{children}</strong>
  }
};

export default function BlogPost({ post }) {
  return (
    <KyroRichTextRenderer 
      content={post.content} 
      components={customComponents} 
    />
  );
}

Using with Tailwind Typography

If you use the Tailwind @tailwindcss/typography plugin, you don't even need to write custom overrides. You can simply wrap the default headless output in a .prose class, and Tailwind will style all the semantic HTML automatically:

import { KyroRichTextRenderer } from 'kyro-rich-text-react';

export default function BlogPost({ post }) {
  return (
    <div className="prose prose-blue lg:prose-xl mx-auto">
      <KyroRichTextRenderer content={post.content} />
    </div>
  );
}

Supported Nodes and Marks

By default, the renderer supports mapping these Tiptap formats to standard HTML tags:

Types (Blocks):

  • doc -> <React.Fragment>
  • paragraph -> <p>
  • heading -> <h1> - <h6>
  • blockquote -> <blockquote>
  • bulletList -> <ul>
  • orderedList -> <ol>
  • listItem -> <li>
  • codeBlock -> <pre><code>
  • horizontalRule -> <hr />
  • hardBreak -> <br />
  • image -> <img>

Marks (Inline):

  • bold -> <strong>
  • italic -> <em>
  • strike -> <s>
  • code -> <code>
  • underline -> <u>
  • link -> <a>

If your Kyro CMS uses custom blocks in the rich text editor, you can handle them by adding a new key to the types object in your components prop matching your custom block's type string.


License

MIT