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.

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> ); };

Each flattened content block object contains:

PropertyTypeDescription
_idstringThe unique identifier of the content entry
typestringThe content type identifier
fieldsRecord<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 and slots serve different purposes:

FeatureContent BlocksSlots
PurposeEmbed structured data (content entries)Embed rendered components
OutputRaw data you render yourselfPre-rendered React components
Defined inContent types (fields)Component definitions (slots)
Use caseData-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.