@natilon/astro-blocks
v0.2.0
Published
Built-in block renderer components for Natilon CMS sites built with Astro.
Readme
@natilon/astro-blocks
Built-in block renderer components for Natilon CMS sites built with Astro. Ships all 12 standard block types out of the box. Override any block or add custom types via the components prop — no configuration files.
Install
npm i @natilon/astro-blocksUsage
---
import BlockRenderer from "@natilon/astro-blocks";
const { entry } = Astro.props;
---
<BlockRenderer blocks={entry.data.blocks} />blocks is the array from your Astro content collection entry — whatever entry.data.blocks contains after the CMS writes it.
Built-in block types
| Type | Renders as | Key properties |
|---------------|-------------------------------------|---------------------------------------------------------------|
| heading | <h2>–<h4> | text (required), level (2/3/4) |
| text | Rich HTML fragment | content (required, HTML) |
| html | Raw HTML fragment | content (required, HTML) |
| image | <figure> + <img> | src (required), alt, width |
| text-image | Two-column text + image | content (required), image (required), imageDescription, reversed |
| blockquote | <blockquote> | content (required), cite |
| list | <ul> or <ol> | items (required, JSON array), ordered |
| button | <a> styled as button | text (required), href (required), style |
| divider | <hr> | (none) |
| spacer | Empty <div> with height | size (tall/short) |
| video-embed | Embedded YouTube or Mux player | src (required), provider (youtube/mux) |
| columns | CSS Grid column layout | columnCount (2/3/4), children (nested blocks) |
Overriding built-in blocks
Pass a components map to replace any built-in renderer. Your component receives the same { properties, children?, components? } props.
---
import BlockRenderer from "@natilon/astro-blocks";
import CdnImage from "./components/CdnImage.astro";
// CdnImage replaces the default <img> renderer with CDN-optimised output.
// All other block types use their built-in renderers.
---
<BlockRenderer
blocks={entry.data.blocks}
components={{ image: CdnImage }}
/>Override component interface:
---
// components/CdnImage.astro
interface Props {
properties: Record<string, unknown>;
components?: Record<string, unknown>; // forwarded for recursion
}
const { properties: p } = Astro.props;
const src = String(p.src ?? "");
const alt = String(p.alt ?? "");
---
{src && <figure><img src={src} alt={alt} loading="lazy" /></figure>}Adding custom block types
Define the block schema in cms.config.mjs (so the editor shows it in the block palette), then pass your renderer via components:
// cms.config.mjs
blocks: {
hero: {
label: "Hero",
icon: "fa-star",
properties: {
heading: { type: "text", label: "Heading", required: true },
image: { type: "image", label: "Background" },
},
defaults: { heading: "Welcome" },
},
},---
// src/components/blocks/hero.astro
interface Props {
properties: Record<string, unknown>;
}
const { properties: p } = Astro.props;
---
<section class="hero" style={`background-image:url(${p.image})`}>
<h1>{p.heading}</h1>
</section>---
// src/pages/[slug].astro
import BlockRenderer from "@natilon/astro-blocks";
import HeroBlock from "../components/blocks/hero.astro";
---
<BlockRenderer
blocks={entry.data.blocks}
components={{ hero: HeroBlock }}
/>Custom blocks sit alongside built-ins — both appear in the editor palette and are rendered transparently.
Nested blocks (columns)
The columns block renders child block arrays recursively. Custom block types passed via components are available inside columns too — BlockRenderer forwards the map automatically.
<BlockRenderer
blocks={entry.data.blocks}
components={{ hero: HeroBlock, image: CdnImage }}
/>
<!-- hero and CdnImage work inside column children too -->Props reference
<BlockRenderer>
| Prop | Type | Default | Description |
|--------------|-----------------------------------|---------|------------------------------------------|
| blocks | Block[] | required | Array from entry.data.blocks |
| components | Record<string, AstroComponent> | {} | Override or extend built-in block types |
| nested | boolean | false | Set by columns for recursive renders |
Block shape
interface Block {
id: string;
type: string; // matches a built-in or components key
properties: Record<string, unknown>; // editor-set values
children?: Block[][]; // columns only
}