Content Block Parameter Utilities
Content block parameters allow embedding structured content entries inline within a composition component. They reference Uniform content entries (created via content types) and store them as parameter values.
Using flattenValues with content blocks#
Use flattenValues from @uniformdev/canvas to extract content block data, exactly the same way you would with asset parameters:
import { flattenValues } from "@uniformdev/canvas";
import { ComponentParameter, ComponentProps } from "@uniformdev/next-app-router/component";
type ContentBlockValue = {
_id: string;
type: string;
fields: Record<string, { type: string; value: unknown }>;
};
type TestimonialSectionProps = {
testimonials?: ComponentParameter<ContentBlockValue[]>;
featuredTestimonial?: ComponentParameter<ContentBlockValue[]>;
};
export const TestimonialSection = ({
parameters: { testimonials, featuredTestimonial },
}: ComponentProps<TestimonialSectionProps>) => {
// Multiple content blocks: returns an array
const allTestimonials = flattenValues(testimonials);
// Single content block: returns a single object
const featured = flattenValues(featuredTestimonial, { toSingle: true });
return (
<section>
{featured && (
<blockquote className="text-xl italic border-l-4 pl-4">
<p>{featured.fields?.quote?.value as string}</p>
<cite>{featured.fields?.author?.value as string}</cite>
</blockquote>
)}
<div className="grid grid-cols-2 gap-6 mt-8">
{allTestimonials?.map((item, i) => (
<div key={i} className="p-4 border rounded">
<p>{item?.fields?.quote?.value as string}</p>
<p className="text-sm text-gray-500">
{item?.fields?.author?.value as string}
</p>
</div>
))}
</div>
</section>
);
};
Accessing content block fields#
Each flattened content block object contains:
| Property | Type | Description |
|---|---|---|
_id | string | The unique identifier of the content entry |
type | string | The content type identifier |
fields | Record<string, { type: string; value: unknown }> | The content entry's field values |
Access individual fields through the fields property:
const block = flattenValues(contentBlockParam, { toSingle: true });
// Access text fields
const title = block?.fields?.title?.value as string;
// Access number fields
const price = block?.fields?.price?.value as number;
// Access boolean fields
const isActive = block?.fields?.isActive?.value as boolean;
Content blocks vs. slots#
Content blocks and slots serve different purposes:
| Feature | Content Blocks | Slots |
|---|---|---|
| Purpose | Embed structured data (content entries) | Embed rendered components |
| Output | Raw data you render yourself | Pre-rendered React components |
| Defined in | Content types (fields) | Component definitions (slots) |
| Use case | Data-driven rendering (cards, lists, metadata) | Component composition (layouts, sections) |
Use content blocks when you need raw data to render in a custom way. Use slots when you want the full component rendering pipeline.