Template Content
On this page, you'll learn how to template content from the Prismic API in your Next.js application.
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:
<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>
:
<PrismicRichText 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
Prismic’s development kits offer three types of API request functions:
Get-single requests, such as getFirst()
and getByUID()
, which return a single document
object.
Get-all requests, such as dangerouslyGetAll()
and getAllByType()
, which return a results
array made up of document
objects.
Paginated requests, such as get()
and getByType()
, which return a results
array plus pagination information.
By default, a paginated request will return 20 documents, but you can adjust the page size with the pageSize
API option to return up to 100 documents. Get-all requests will run recursively to fetch all matching documents.
In Next.js, you might use that data like this:
<h3>{response.results[0].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:
"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..."
}
}
]
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.
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>
’scontext
prop.
A simple slice component could look like this:
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.
<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:
<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/client
provides a function to convert a date or timestamp field from Prismic into a JavaScript date object.
npm install @prismicio/client
With the client package installed, you can handle date and timestamp fields like in the following example:
import * as prismic from '@prismicio/client'
<p>{prismic.asDate(document.data.example_date).getFullYear()}</p>
// <p>2021</p>
<time
datetime={prismic
.asDate(document.data.example_timestamp)
.toISOString()}
>
{prismic.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.
"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.
<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:
"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.
<div
dangerouslySetInnerHTML="{{"
__html:
document.data.example_embed.html,
}}
/>
The <iframe>
may have a default height and width defined by the oEmbed provider. You can style the iframe’s height and width in your global CSS:
iframe {
width: 100%;
height: auto;
}
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.
"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.
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
:
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.
<PrismicImage>
from@prismicio/react
asImageSrc()
,asImageWidthSrcSet()
, orasImagePixelDensitySrcSet()
from@prismicio/client
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).
"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
.
import { PrismicRichText } from "@prismicio/react";
<PrismicRichText field={document.data.example_rich_text} />;
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.
import { PrismicText } from "@prismicio/react";
<PrismicText field={document.data.example_rich_text} />;
Link
The link field renders an internal or external link.
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:
For each of those links we considered that it had a Link text
property enabled to manage the link label.
"example_link": {
"id": "X9C65hEAAEFIAuLo",
"type": "page",
"tags": [],
"slug": "another-document",
"lang": "en-us",
"uid": "another-document",
"link_type": "Document",
"isBroken": false,
"text" : "Default Label"
}
You can template a link using @prismicio/next
’s <PrismicNextLink>
component. It renders a link using next/link
and automatically resolves internal and external links.
If the link has display text, it will automatically be rendered:
import { PrismicNextLink } from "@prismicio/next";
// With default text property
<PrismicNextLink field={document.data.example_link} />;
// Overriding with custom children
<PrismicNextLink field={document.data.label_link}>
Custom Label
</PrismicNextLink>;
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 type in your content relationship field.
- Then, the API ID of the field that you want to retrieve.
If you have a page 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:
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:
"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:
<p>
Written by{" "}
{
document.data.example_content_relationship.data
.author_name
}
</p>
// <strong>Written by Jane Doe</strong>
Group
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.
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:
<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.