# Content Block Parameter Utilities

> How to work with content block parameters using flattenValues from the Uniform canvas SDK.

Source: https://docs.uniform.app/docs/sdk/parameter-utilities/content-block-parameters

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](./asset-parameters):

```tsx
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:

```tsx
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.
