# How to connect content data to front-end components

Once you have a component library, the next step of building a headless platform is connecting your content models to your front-end components. Your website will probably have templated and non-templated pages. &#x20;

The process for building a templated page is relatively straightforward. Dynamically building a non-templated page is more complex as page content and layout will vary, depending on what the content author has selected.&#x20;

## Templated pages&#x20;

Authors will see pre-defined content fields when composing a templated page. They won't be able to reorder components or otherwise modify the layout of the page.&#x20;

Let's take a blog post as an example. Users can input the title, date, summary, and body of the blog post.&#x20;

<figure><img src="https://882838265-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fq7UE1cAwz12WuyrFSyXF%2Fuploads%2FeXPZZQOTS8er5cZP93Nq%2Fblog3.png?alt=media&#x26;token=514106ab-2f3f-4b31-9ffa-8e2ae2d26a39" alt="" width="514"><figcaption><p>A templated page has pre-specified content fields and the page layout is hard-coded. Authors can't reorder components or add different fields.</p></figcaption></figure>

Sanity would return a JSON object that looks like this:

{% code overflow="wrap" %}

```javascript
{
  "blogTitle": "Headless CMS essentials: Live Preview, featuring Sanity.io",
  "content": 
  "publishDate": "2023-03-22",
  "slug": "headless-live-preview",
  "summary": "By using a live preview in your headless CMS, content authors can have the best of both worlds: a familiar, visual editing experience combined with improved performance, flexibility, and scalability.",
  //... additonal fields have been omitted for brevity
}
```

{% endcode %}

To generate the blog post as a page, you need to map the JSON fields to the right components and map the keys from the JSON file to the appropriate place in the page template.&#x20;

```jsx
const BlogPost = ({ data }) => {

  const {
    blogTitle,
    content,
    publishDate,
    summary,
  } = data.page

  return (
    <StyledBlogPostPage>
      <StyledArticle>
        <StyledReadTime>
          {publishDate}
        </StyledReadTime>
        <h1>{blogTitle}</h1>
        <StyledSummary>
          <p>{summary}</p>
        </StyledSummary>
        <article>{content}</article>
      </StyledArticle>
    </StyledBlogPostPage>
  )
}
```

The result is a static HTML file of our blog post page.

<figure><img src="https://882838265-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fq7UE1cAwz12WuyrFSyXF%2Fuploads%2FYcqTWAGFoDMkb5mfo8Si%2Fimage.png?alt=media&#x26;token=6b3350fb-339c-4465-91af-300f6cec9ab7" alt="" width="375"><figcaption></figcaption></figure>

## Non-templated pages

Authors can choose from a selection of components and page modules when composing a non-templated page. They can add and move content around and change the page layout.&#x20;

To build a non-templated page, we need to dynamically connect the JSON data from the CMS to our front-end components. The magic is in a single function we call **`buildComponent`**.&#x20;

You'll likely see different implementations across various frameworks and starter repos. We'll walk through our general approach by explaining how we can do this in Next.js.

### How to use `buildComponent` in Next.js

Let's look at this example JSON containing CMS content data:

{% code title="Sample JSON from CMS" overflow="wrap" %}

```json
{
  "_key": "6288f6544a9e",
  "_type": "Quote", // Content model name should match component name
  // Content model fields should match props in components:
  "attribution": "Lance Martel, CIO, Staples Canada",
  "quotation": "Rangle gave us permission to prioritize the customer because true innovation is anchored by the customer…and how we drive better experiences for them."
}
```

{% endcode %}

Import all the components you need to dynamically build a given page. These should be your **CMS module** components from your component library.

{% code title="buildComponent.jsx" %}

```jsx
import {
  Accordion,
  Footer,
  GalleryCarousel,
  HeroBanner,
  Quote,
  // ... all other components
} from '../component-library'
```

{% endcode %}

Map the content models in your CMS to the front-end components in your component library.&#x20;

{% hint style="success" %}
**Name your content models and components so their field names and prop names match, respectively.**&#x20;

This is critical for matching content data from your CMS to the appropriate components in your component library, to dynamically generate a non-templated page.
{% endhint %}

If the name of a content model in your JSON doesn't match the name of its corresponding component, you'll need to explicitly define a map object to pair the names of your content model and component.

{% code title="buildComponent.jsx" overflow="wrap" %}

```jsx
const componentsMap = {
  Accordion,
  Footer,
  GalleryCarousel,
  MainHero: HeroBanner, // explicitly map content models to components if their names don't match
  Quote,
  // ... all other components
}

const componentSelector = (componentType) => {
  return components[componentType]
}
```

{% endcode %}

Pass the component names and props from the CMS to generate the dynamic component.

{% code title="buildComponent.jsx" overflow="wrap" lineNumbers="true" %}

```jsx
export const buildComponent = ({_type, ...props}) => {
  if (!_type) {
    throw new Error('Object does not have a '_type' property')
  }

  const Component = componentsMap[_type]
  if (!Component) {
    throw new Error(`No component is registered for type:'${_type}`)
  }
  return <Component {...props} />
}
```

{% endcode %}

When we put everything together, `buildComponent.jsx` looks like this:

{% code title="buildComponent.jsx" overflow="wrap" lineNumbers="true" %}

```jsx
import {
  Accordion,
  Footer,
  GalleryCarousel,
  HeroBanner,
  Quote,
} from '../component-library'

const componentsMap = {
  Accordion,
  Footer,
  GalleryCarousel,
  HeroBanner,
  Quote,
}

const componentSelector = (componentType) => {
  return components[componentType]
}

export const buildComponent = ({_type, ...props}) => {
  if (!_type) {
    throw new Error('Object does not have a '_type' property')
  }

  const Component = componentsMap[_type]
  if (!Component) {
    throw new Error(`No component is registered for type:'${_type}`)
  }
  return <Component {...props} />
}
```

{% endcode %}

You can now use this function whenever you need to dynamically create components on a page template.&#x20;

<pre class="language-jsx" data-title="[...slug].jsx" data-overflow="wrap" data-line-numbers><code class="lang-jsx"><strong>import { buildComponent } from '../util/buildComponent.jsx'
</strong><strong>
</strong><strong>const Page = ({ data }) => {
</strong>  const { modules } = data.page
  return (
    &#x3C;div>
      {modules.map(module => buildComponent(module))}
    &#x3C;/div>
  )
}
</code></pre>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://tbw.rangle.io/headless-cms-playbook/static-site-generators/how-to-connect-content-data-to-front-end-components.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
