React renderer for Strapi v5 Blocks content — supports all standard blocks plus Better Blocks features: color, highlight, text alignment, nested lists, to-do lists, tables, media embeds, image captions, and more.
- Why?
- Compatibility
- Installation
- Usage
- Supported Blocks
- Supported Modifiers
- Custom Renderers
- TypeScript
- Contributing
- License
The official @strapi/blocks-react-renderer doesn't support the features that the Better Blocks plugin adds to the Strapi editor — color marks, text alignment, to-do lists, tables, media embeds, and more.
This package is a drop-in replacement that renders all Better Blocks features out of the box — no configuration needed.
| Strapi Version | Renderer Version | React Version |
|---|---|---|
| v5.x | v0.x | ≥ 17 |
# Using yarn
yarn add @k11k/better-blocks-react-renderer
# Using npm
npm install @k11k/better-blocks-react-rendererPeer dependencies: react >= 17
import { BlocksRenderer } from '@k11k/better-blocks-react-renderer';
// Basic — renders all blocks including color/highlight
<BlocksRenderer content={blocks} />;That's it. All Better Blocks features — colors, tables, to-do lists, media embeds, alignment, and more — work automatically.
| Block | Default element | Source |
|---|---|---|
paragraph |
<p> |
Strapi core |
heading (1–6) |
<h1>–<h6> |
Strapi core |
list (ordered/unordered/todo) |
<ol> / <ul> |
Strapi core + Better Blocks |
list-item |
<li> |
Strapi core |
link |
<a> |
Strapi core |
quote |
<blockquote> |
Strapi core |
code |
<pre><code> |
Strapi core |
image |
<figure><img> |
Strapi core |
horizontal-line |
<hr> |
Better Blocks |
table |
<table> |
Better Blocks |
media-embed |
<iframe> (16:9) |
Better Blocks |
| Property | Applies to | Description |
|---|---|---|
textAlign |
paragraph, heading, quote | Text alignment (left, center, right, justify) |
lineHeight |
paragraph, heading, quote | CSS line-height value (e.g. 1.5, 2.0) |
indent |
paragraph, heading, quote | Block indentation level (marginLeft: N * 2rem) |
indentLevel |
list | Cycling list-style-type per nesting depth |
format |
list | ordered, unordered, or todo |
checked |
list-item (in todo lists) | Checkbox state (true/false) |
target |
link | _blank for new-tab links |
rel |
link | noopener noreferrer for new-tab links |
caption |
image | Text displayed below the image |
imageAlign |
image | Image alignment (left, center, right) |
url |
media-embed | Embed URL (YouTube/Vimeo iframe src) |
originalUrl |
media-embed | Original user-provided URL |
| Modifier | Default element | Source |
|---|---|---|
bold |
<strong> |
Strapi core |
italic |
<em> |
Strapi core |
underline |
<span> |
Strapi core |
strikethrough |
<del> |
Strapi core |
code |
<code> |
Strapi core |
uppercase |
<span style={{textTransform}}> |
Better Blocks |
superscript |
<sup> |
Better Blocks |
subscript |
<sub> |
Better Blocks |
color |
<span style={{color}}> |
Better Blocks |
backgroundColor |
<span style={{backgroundColor}}> |
Better Blocks |
fontFamily |
<span style={{fontFamily}}> |
Better Blocks |
fontSize |
<span style={{fontSize}}> |
Better Blocks |
Override any block type with your own component:
<BlocksRenderer
content={blocks}
blocks={{
paragraph: ({ children, style }) => (
<p className="my-paragraph" style={style}>
{children}
</p>
),
heading: ({ children, level, style }) => {
const Tag = `h${level}`;
return <Tag style={style}>{children}</Tag>;
},
link: ({ children, url, target, rel }) => (
<a href={url} target={target} rel={rel}>
{children}
</a>
),
image: ({ image, caption, imageAlign }) => (
<figure style={{ textAlign: imageAlign }}>
<img src={image.url} alt={image.alternativeText || ''} loading="lazy" />
{caption && <figcaption>{caption}</figcaption>}
</figure>
),
'list-item': ({ children, checked }) =>
checked !== undefined ? (
<li style={{ listStyle: 'none' }}>
<input type="checkbox" checked={checked} readOnly /> {children}
</li>
) : (
<li>{children}</li>
),
'horizontal-line': () => <hr className="my-divider" />,
table: ({ children }) => <table className="my-table">{children}</table>,
'table-header-cell': ({ children }) => <th className="my-th">{children}</th>,
'table-cell': ({ children }) => <td className="my-td">{children}</td>,
'media-embed': ({ url }) => (
<div className="video-wrapper">
<iframe src={url} allowFullScreen title="Embedded media" />
</div>
),
}}
/>Override any text modifier with your own component:
<BlocksRenderer
content={blocks}
modifiers={{
bold: ({ children }) => <strong className="font-bold">{children}</strong>,
color: ({ children, color }) => <span style={{ color }}>{children}</span>,
backgroundColor: ({ children, backgroundColor }) => (
<mark style={{ backgroundColor }}>{children}</mark>
),
}}
/>All types are exported:
import type {
BlocksContent,
BlocksRendererProps,
BlockNode,
TextNode,
LinkNode,
ListNode,
ListItemNode,
ParagraphNode,
HeadingNode,
QuoteNode,
CodeNode,
ImageNode,
HorizontalLineNode,
TableNode,
TableRowNode,
TableCellNode,
TableHeaderCellNode,
MediaEmbedNode,
TextAlign,
CustomBlocksConfig,
CustomModifiersConfig,
} from '@k11k/better-blocks-react-renderer';Contributions are welcome! The easiest way to get started is with Docker:
# Clone the repository
git clone https://github.com/k11k-labs/better-blocks-react-renderer.git
cd better-blocks-react-renderer
# Start the playground with Docker
cd playground
docker compose upThis will start a Strapi v5 instance with the Better Blocks plugin and a React app that renders the content — all pre-configured with a showcase article.
- Strapi admin: http://localhost:1337/admin (login:
admin@example.com/admin12#) - React app: http://localhost:5173
- Make changes to the renderer source in
src/ - Rebuild:
yarn build(from repo root) - The React app picks up the new build automatically
# Build the renderer
yarn install && yarn build
# Start Strapi
cd playground/strapi && cp .env.example .env && npm install && npm run dev
# Start the React app (in another terminal)
cd playground/react-app && npm install && npm run devyarn test # Run tests
yarn test:ts # Type check
yarn lint # Check formatting- GitHub Issues — Bug reports and feature requests
- @k11k/strapi-plugin-better-blocks — Strapi plugin that extends the Blocks editor with colors, tables, to-do lists, media embeds, and more
- @strapi/blocks-react-renderer — Official Strapi renderer (standard blocks only)
