Template Content

On this page, you'll learn how to template content from the Prismic API in your Next.js application.


Before you proceed

This article assumes that you have queried your API and saved the document object in a variable, as described in Fetch Data.

Intro to templating

Content from Prismic comes in different types. Some are simple fields, like Numbers or Booleans. Others are structured fields, like Titles, Rich Text, and Links.

Simple field types can be used directly in your application:

Copy
<span>{document.data.example_number}</span> 
// <span>42</span>

The @prismicio/react package includes components for rendering structured fields. To render Rich Text, for instance, you can use <PrismicRichText>:

Copy
<PrismicText field={document.data.example_title} />
// <h2>Hello World!</h2>

To get started, let's look at the structure of the API response.

The structure of the API response

When you use Prismic's query methods, you will see three different types of API responses:

  • paginated responses, which return a response object
  • get-all responses, which return a results array
  • get-single responses, which return a document object

These are all part of the same structure: the response object contains the results array, in which each item is a document object.

Here's more detail about what that each looks like:

The response object

When you perform a query using a paginated method, like getByType(), you will get a response object containing pagination information and an array of up to 100 API results. Here is a truncated example of an API response containing some simple fields:

Copy
{
  "page": 1,
  // Metadata for this query
  // ...
  "results": [
    {
      "uid": "example-document",
      // Metadata for this result
      // ...
      " data": {
        "example_date": "2020-12-10",
        "example_timestamp": "2020-12-10T04:05:09+0000",
        "example_color": "#c7ab5d",
        "example_number": 74,
        "example_key_text": "Example Key Text Value",
        "example_select": "North",
        "example_boolean": true
      }
    }
    // The rest of the documents
    {...},
    {...},
    {...},
  ]
}

If you store the response in a variable called response, you might access a single data point like this:

Copy
response.results[0].data.example_key_text
// Example Key Text Value

In React, you might use that like this:

Copy
<h3>{response.results[0].data.example_key_text</h3>
// <h3>Example Key Text Value</h3>

Or, you might loop over the results array and template each item, like this:

Copy
<ul>
  {response.results.map((document) => (
    <li key={document.id}>{document.data.example_key_text}</li>
  ))}
</ul>

The most important property on the response object is the results array.

The results array

When you perform a query using a get-all method, such as getAllByType(), you will get an array containing all matching results. (If you use a paginated get method, it will include a results array with up to 100 documents.)

Here is a truncated example of an API response using getAllByType():

Copy
[
  {
    "uid": "example-blog-post",
    "type": "blog_post",
    "data": {
      "example_date": "2020-12-10",
      "example_color": "#c7ab5d",
      "example_key_text": "Example Key Text Value"
    }
  }
  // The rest of the documents
  {...},
  {...},
  {...},
]

If you store the response in a variable called results, you might access a single data point like this:

Copy
results[0].data.example_key_text
// Example Key Text Value

In React, you might use it like this:

Copy
<h3>{results[0].data.example_key_text}</h3>
// <h3>Example Key Text Value</h3>

The results array is an array of document objects.

The document object

The query methods getSingle()getByUID(), and getByID() will return a document object, which contains the data for an individual document directly.

Here's a truncated example of the response for those queries:

Copy
{
  "uid": "about",
  // Metadata for this result
  // ...
  "data": {
    "example_date": "2020-12-10",
    "example_color": "#c7ab5d",
    "example_key_text": "Example Key Text Value"
  }
}

With a single document query, you might access your data like this:

Copy
<h3>{document.data.example_key_text</h3>
// <h3>Example Key Text Value</h3>

Slices

Slices are repeatable, rearrangeable content sections. The best practice for working with Slices is creating reusable components and passing down the data as props.

On the document object, Slices are stored in the slices or body array, like so:

Copy
"slices": [
  {
    "slice_label": null,
    "items": [
      {...}
    ],
    "primary": {
      "example_key_text": "Some text..."
    }
  },
  {
    "slice_type": "image_gallery",
    "slice_label": null,
    "items": [
      {...}
    ],
    "primary": {
      "example_key_text": "Some more text..."
    }
  }
]

Other names for the Slice Zone property

Most documents have one Slice Zone stored in the slices property. However, you can change the name of this property in your Custom Type.

To render Slices, use the <SliceZone> component from @prismicio/react by passing an array of Slices from the API and a list of React components for each type of Slice. In the following example, the components are imported from a library of Slices exported from the slices/index.js file.

Copy
import { SliceZone } from '@prismicio/react'
import { components } from '../slices'

const Page = ({ page }) => {
  return (
    <SliceZone slices={page.data.slices} components={components} />
  );
};

Each Slice component will receive the following props that can be used to display the Slice’s content.

  • slice: The Slice object being rendered.
  • index: The index of the Slice within the Slice Zone.
  • slices: The list of all Slice objects in the Slice Zone.
  • context: Arbitrary data passed to the <SliceZone>'s context prop.

A simple Slice component could look like this:

Copy
function TextSlice({ slice }) {
  return (
    <section>
      <PrismicRichText field={slice.primary.text} />
    </section>
  )
}

Simple fields

The content for each Prismic field can be a simple primitive value or an object. The simple fields can be injected directly into your app since their value is either a string, a number, or a boolean. Here are the simple fields:

  • Color
  • Key Text
  • Number
  • Select
  • Boolean
  • Date
  • Timestamp

Here's an example of how to use the Number field. You can template the other simple fields similarly.

Copy
<span>{document.data.example_number}</span>
// <span>42</span>

Retrieving the Color field is similar. Here we can see how to do inline styling in React:

Copy
<h3 style={{ color: document.data.example_color }}>
  My favorite color is Purple
</h3>

// <h3 style="color: #A020F0;">
//   My favorite color is Purple
// </h3>

Date and Timestamp

The Date and Timestamp fields from Prismic are strings. The raw response for each of these fields has the following formats:

  • Date: YYYY-MM-DD
  • Timestamp: YYYY-MM-DDTHH:MM:SS+0000

A package named @prismicio/helpers provides a function to convert a Date or Timestamp field from Prismic into a JavaScript date object.

Copy
npm install @prismicio/helpers

With the helpers package installed, you can handle Date and Timestamp fields like in the following example:

Copy
import * as prismicH from '@prismicio/helpers'

<p>{prismicH.asDate(document.data.example_date).getFullYear()}</p>
// <p>2021</p>

<time
  datetime={prismicH
  .asDate(document.data.example_timestamp)
  .toISOString()}
>
  {prismicH.asDate(document.data.example_timestamp).toLocaleString()}
</time>
// <time datetime="2018-01-16T13:46:15.000Z">
//   01/16/2018, 1:46:15 PM
// </p>

GeoPoint

The GeoPoint field is served as an object with two properties: latitude and longitude.

Copy
"example_geopoint": {
  "latitude": 48.85392410000001,
  "longitude": 2.2913515000000073,
}

Here is an example of how to retrieve the latitude and longitude coordinates for a GeoPoint field.

Copy
<p>
  {
    'My location is ' +
    document.data.example_geopoint.latitude.toFixed(2) +
    ', ' +
    document.data.example_geopoint.longitude.toFixed(2)
  }
</p>


// <p>My location is: 48.85, 2.29</p>

Embed

Here's an API response of the Embed field:

Copy
"example_embed": {
  "version": "1.0",
  "url": "https://prismic.io",
  "type": "link",
  "title": "Make your website editable for the whole team - Prismic",
  "provider_name": null,
  "thumbnail_url": "https://images.prismic.io/prismic-website/6e49007fec52f99861047cdd55b3ab190ea04295_dev-landing-page-image.png?auto=compress,format",
  "html": "<div data-type='unknown'><a href='https://prismic.io'><h1>Make your website editable for the whole team - Prismic</h1></div>",
  "embed_url": "https://prismic.io/"
}

You can display an Embed field using the html property on the response. To render HTML, use React's dangerouslySetInnerHTML prop. Learn more about dangerouslySetInnerHTML() in the React documentation.

Copy
<div
  dangerouslySetInnerHTML={{
    __html: document.data.example_embed.html,
  }}
/>

Images

The Image field returns an object with data about the image, including a URL for your image (hosted on Prismic's servers) and alt text.

Copy
"example_image": {
  "dimensions": {
    "width": 1920,
    "height": 1302
  },
  "alt": "Pink flowers on a tree",
  "copyright": null,
  "url": "https://images.prismic.io/sm-20201204-2/7d1fba99-5bec-4d59-b8eb-402706e2d36c_a-pril-62u95KgB49w-unsplash.jpg?auto=compress,format"
}

You can template an image using @prismicio/next's <PrismicNextImage> component. It renders an optimized image using next/image and Prismic’s built-in imgix Image CDN integration.

Copy
import { PrismicNextImage } from '@prismicio/next'

<PrismicNextImage field={doc.data.example_image} />

The component uses the field’s URL, dimensions, and alt text to generate its output.

Images can be transformed using Prismic’s built-in imgix integration and the imgixParams prop. This allows you to resize, crop, recolor, and more. See imgix’s URL API Reference for a full list of available information.

The following example converts the image to grayscale with sat: -100:

Copy
import { PrismicNextImage } from '@prismicio/next'

<PrismicNextImage field={doc.data.example_image} imgixParams={{ sat: -100 }} />

Alternatively, images can be templated using one of the following components or helpers. <PrismicNextImage> is recommended for most cases, however.

Rich Text and Titles

Rich Text and Titles are delivered in an array that contains information about the text structure. Here's an example of the API response of the Rich Text field (Title fields follow the same format).

Copy
"example_rich_text": [
  {
    "type": "paragraph",
    "text": "Example Rich Text Value",
    "spans": [
      {
        "start": 8,
        "end": 17,
        "type ": "strong"
      }
    ]
  }
]

Output as React components

To render Rich Text and Title fields as React components, use the <PrismicRichText> component from @prismicio/react.

Copy
import { PrismicRichText } from '@prismicio/react'

<PrismicRichText field={document.data.example_rich_text} />

Using custom React components

To modify the output of a Rich Text field, provide a list of component overrides to the components prop. The list of components maps an element type to its React component. Here is an example using custom components for first-level headings and paragraphs.

<PrismicRichText
  field={document.data.example_rich_text}
  components={{
    heading1: ({ children }) => <Heading>{children}</Heading>,
    paragraph: ({ children }) => <p className="paragraph">{children}</p>,
  }}
/>

Learn more about customizing Rich Text output in HTML Serializing.

Output as plain text

The <PrismicText> component from @prismicio/react will convert and output the text in the Rich Text or Title field as a string.

Copy
import { PrismicText } from '@prismicio/react'

<PrismicText field={document.data.example_rich_text} />

Link

The link field renders an internal or external link.

Links vs Content Relationships

Although these two fields are similar, it is important to note the difference to know how to differentiate them and know in which case to use each one.

The Link field allows you to link to an external webpage, an internal Prismic document, or an item in your Media Library (like a PDF). The Link field is used to create a link (i.e. an a element).

The Link field cannot be constrained by Custom Type, so you do not know the structure of the document you are linking to. For that reason, you should avoid fetching linked content with the Link field. Instead, use the Content Relationship field.

The Content Relationship field allows you to link specifically to an internal Prismic document constrained by Custom Type. Content Relationship fields are used to pull data from another document.

Here's what the content of a Link field looks like from the API, depending on the type of content you add. This field has an API ID example_link, the first one links to another document with the UID another-document and the type page, the second one has a web URL, and the third one links to a media item:

  • Link to another document
  • Link to web
  • Link to media item
Link to another document
Copy
"example_link": {
  "id": "X9C65hEAAEFIAuLo",
  "type": "page",
  "tags": [],
  "slug": "another-document",
  "lang": "en-us",
  "uid": "another-document",
  "link_type": "Document",
  "isBroken": false
}
Link to web
Copy
"example_link": {
  "link_type": "Web",
  "url": "https://prismic.io"
}
Link to media item
Copy
"example_link": {
  "link_type": "Media",
  "name": "cool_pic.png",
  "kind": "image",
  "url": "https://images.prismic.io/slicemachine-blank/30d6602b-c832-4379-90ef-   100d32c5e4c6_cool_pic.png?auto=compress,format",
  "size": "181944",
  "height": "1536",
  "width": "2048"
},

<PrismicLink> automatically resolves your external links, but you need to use Next's Link component to create links between internal pages.

You need to configure <PrismicLink> to use Next.js' <Link> component — as described in the setup step. You'll wrap your app with <PrismicProvider> in the _app.js file and configure the internalLinkComponent prop to use Next's <Link>.

/pages/_app.js
Copy
import Link from 'next/link'
import { PrismicProvider } from '@prismicio/react'
import { PrismicPreview } from '@prismicio/next'
import { linkResolver, repositoryName } from '../prismicio'

export default function App({ Component, pageProps }) {
  return (
    <PrismicProvider
      linkResolver={linkResolver}
      internalLinkComponent={({ href, children, ...props }) => (
        <Link href={href}>
          <a {...props}>
            {children}
          </a>
        </Link>
      )}
    >
      <PrismicPreview repositoryName={repositoryName}>
        <Component {...pageProps} />
      </PrismicPreview>
    </PrismicProvider>
  )
}

After that, pass your Link field to <PrismicLink>, and it will automatically render the correct route:

Copy
import { PrismicLink } from '@prismicio/react'

<PrismicLink field={document.data.example_link}>Example Link</PrismicLink>

Content Relationship

To pull in content from another document, you must fetch that content in your API query using the graphQuery or fetchLinks option.

  • First, reference the API ID of the Custom Type in your Content Relationship field.
  • Then, the API ID of the field that you want to retrieve.

If you have a Custom Type called blog that includes a Content Relationship field called example_content_relationship linked to a Custom Type called author where you want to retrieve a field that has an API ID of author_name, you query it like so:

Copy
export const getStaticProps = async ({ previewData }) => {
  const client = createClient({ previewData })

  const document = await client.getByUID('blog', 'my-blog-post', {
    fetchLinks: 'author.author_name',
  })

  return {
    props: { document },
  }
}

Once you have adjusted your API query, the linked content will appear in a data object nested in the Link or Content Relationship field:

Copy
"example_content_relationship": {
  "id": "X9C65hEAAEFIAuLo",
  "type": "blog",
  "tags": [],
  "slug": "another-page-title",
  "lang": "en-us",
  "uid": "my-blog",
  "data": {
    "author_name": "Jane Doe"
  },
  "link_type": "Document",
  "isBroken": false
}

You can then render that content:

Copy
<p>
  Written by {document.data.example_content_relationship.data.author_name}
</p>
// <strong>Written by Jane Doe</strong>

Group

Slices vs Groups

Slices and Groups both allow you to create repeatable content templates. Groups are available in the static section of your document, and Slices are available in the Slice Zone. The difference between Groups and Slices is that Groups allow you to repeat a collection of fields, while Slices let you repeat and mix different collections of fields.

A Group field renders an array of content fields. Here's what the API response looks like for a hypothetical Group field modeling a nav menu.

Copy
example_group: [
  {
    example_nav_label: 'Homepage',
    example_nav_link: {...},
  },
  {
    example_nav_label: 'About',
    example_nav_link: {...},
  },
]

To template a Group field use a .map() function to loop over the results. Here's a usage example:

Copy
<ul>
  {document.data.example_group.map((item) => (
    <li key={item.example_key_text}>
      {item.example_key_text}
    </li>
  ))}
</ul>

// <ul>
//   <li>This is some text in a group.</li>
//   <li>And here we have more text.</li>
//   <li>Finally another piece of text.</li>
// </ul>

In React, a key prop should be given to the outer-most component in the .map() function. Give it a value that will be unique among the Group field's items.


Was this article helpful?
Not really
Yes, Thanks

Can't find what you're looking for? Spot an error in the documentation? Get in touch with us on our Community Forum or using the feedback form above.