Template Content

On this page, you'll learn how to display content from the Prismic API in your Nuxt application using these components:

  • <prismic-rich-text />
  • <prismic-text />
  • <prismic-embed />
  • <prismic-image />
  • <prismic-link />
  • <slice-zone />

By the end of this page, you will have content from Prismic displayed in your app.


Intro to templating

Content from Prismic comes in more than a dozen types. Most of these are simple primitive values, like numbers or booleans. Others are more complex structured values, like titles, rich texts, and links.

Most of the examples on this page assume that you have queried a single document from the Prismic API using the usePrismic() hook object and stored it in a variable called document, like so:

Copy
<script setup>
const { client } = usePrismic();
const route = useRoute();

const { data: document } = await useAsyncData("page", async () => {
  const document = await client.getByUID("page", route.params.uid);

  if (document) {
    return document;
  } else {
    throw createError({ statusCode: 404, message: "Page not found" });
  }
});
</script>

With simple content types, you can inject them directly into your application:

Copy
<span>{{ document.data.example_number }}</span>
<!-- <span>74.5</span> -->

For structured content types, we provide special utilities. To render rich text, for instance, we provide a rich text component:

Copy
<prismic-rich-text :field="document.data.example_rich_text" />

To get started, lets look at the structure of raw API response.

The structure of the API response

Multiple documents

When you perform a get-all request to the API, such as client.getAllByType(), you will receive an array of documents.

Copy
[
  {
    uid: 'example_document',
    // ...
    data: {
      example_date: '2020-12-10',
      example_timestamp: '2020-12-10T04:05:09+0000',
      example_color: '#c7ab5d',
      example_number: 74.5,
      example_key_text: 'Example Key Text Value',
      example_select: 'North',
      example_boolean: true,
    }
  },
  // ...
]

A single document

The helper functions client.getSingle(), client.getByUID(), and client.getByID() will return a single document:

Copy
{
  uid: 'example_document',
  // ...
  data: {
    example_date: '2020-12-10',
    example_timestamp: '2020-12-10T04:05:09+0000',
    example_color: '#c7ab5d',
    example_number: 74.5,
    example_key_text: 'Example Key Text Value',
    example_select: 'North',
    example_boolean: true,
  }
}

Slices

Slices are repeatable, rearrangeable content sections. By default, slices are found in the data.slices property your document:

Copy
// document.data.slices
[
  {
    slice_type: 'title_slice',
    slice_label: null,
    items: [{}],
    primary: {
      title: 'Some colorful numbers and birthdays'
    }
  },
  {
    slice_type: 'birthday_slice',
    slice_label: null,
    items: [{}],
    primary: {
      person: 'Alan Turing',
      birthday: '1912-06-23'
    }
  },
  {
    slice_type: 'birthday_slice',
    slice_label: null,
    items: [{}],
    primary: {
      person: 'Grace Hopper',
      birthday: '1906-12-09'
    }
  }
]

Coding slices

Slice components receive four props, which you can use:

  • slice: The content of 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.

Because defining props in Vue.js is verbose, we provide a helper function to do so: getSliceComponentProps(). With it, a simple slice component could look like this:

slices/ExampleSlice/index.vue
Copy
<template>
  <PrismicRichText :field="slice.primary.text" />
</template>

<script setup>
// The array passed to `getSliceComponentProps` is purely optional.
// Consider it a visual hint for you when templating your slice.
defineProps(getSliceComponentProps(["slice", "index", "slices", "context"]));
</script>

Every slice may have a "non-repeatable" and a "repeatable" section. The repeatable section functions just like a group field.

When modeling your slices, Slice Machine provides code snippets that you can copy-paste into your Vue component to template your slice.

Rendering the slice zone

The @nuxtjs/prismic module provides a <slice-zone> component to render slices. Import the slices from your slices directory and pass them to the component along with a slices object from a document from the Prismic API.

pages/index.vue
Copy
<template>
  <slice-zone wrapper="main" :components="components" :slices="document.data.slices" />
</template>

<script setup>
import { components } from "~/slices";

const { client } = usePrismic();
const route = useRoute();

const { data: document } = await useAsyncData("page", async () => {
  const document = await client.getByUID("page", route.params.uid);

  if (document) {
    return document;
  } else {
    throw createError({ statusCode: 404, message: "Page not found" });
  }
});
</script>

On page components, the wrapper prop of the slice zone is mandatory unless you wrap the component yourself. This is required because Nuxt pages must feature a single root element.

Simple content types

The simple content types are:

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

These are represented as either a string, a number, or a boolean, and you can access them directly, like so:

Copy
document.data.example_number
// 74.5

Dates come from the API as a string, in the formay YYYY-MM-DD. To convert a date string to a JavaScript Date object, you can use the built-in $prismic.asDate() method:

Copy
document.data.example_date
// '2020-12-10'

$prismic.asDate(document.data.example_date)
// Thu Dec 10 2020 01:00:00 GMT+0100 (Central European Standard Time)

Geopoints

The geopoint field is served as an object with two properties: latitude and longitude. This is the structure of a geopoint:

Copy
// document.data.example_geopoint
{
  latitude: 48.85392410000001,
  longitude: 2.2913515000000073
},

You can access these properties directly:

Copy
document.data.example_geopoint.latitude
// 48.85392410000001

document.data.example_geopoint.longitude
// 2.2913515000000073

Embeds

This is the structure of an embed field:

Copy
// document.data.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><img src=\"https://images.prismic.io/prismic-website/6e49007fec52f99861047cdd55b3ab190ea04295_dev-landing-page-image.png?auto=compress,format\"><p>Choose your technology. Use the API to fetch content. Empower your content team.</p></a></div>",
  embed_url: "https://prismic.io/"
},

You can template an embed field with the Embed component:

Copy
<prismic-embed :field="document.data.example_embed" />

Images

In Prismic, you can define an image's alt text, copyright, and alternate crops — all of which can also have their own alt text. All of this information is served in the API response. A simple image field might look like this:

Copy
// document.data.example_image
{
  dimensions: {
    width: 1920,
    height: 1302
  },
  alt: null,
  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 with the image component:

Copy
<prismic-image :field="document.data.example_image" />

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 a rich text field (title fields follow the same format):

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

Rich text component

Here's how to render rich text or a title with the rich text component (rich text serializer and wrapper are optional):

Copy
<prismic-rich-text 
  :field="document.data.example_rich_text" 
  :serializer="optionalRichTextSerializer" 
  wrapper="article" 
/>

What is a rich text serializer?

The rich text serializer defines the markup of your rich text. (For example: italic text should have <em> tags.) @nuxtjs/prismic contains a default rich text serializer for standard markup, but you can create your own rich text serializer if you want to customize your markup.

Text component

Here's how to render rich text or a title with the text component (wrapper is optional):

Copy
<prismic-text 
  :field="document.data.example_rich_text" 
  wrapper="article" 
/>

Links in rich text

Links in rich text are resolved with the route resolver defined in your Nuxt app setup.

Links and content relationships

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 content relationship field allows you to link specifically to an internal Prismic document.

Here's an example content relationship (a link takes a similar format):

Copy
// document.data.example_content_relationship
{
  id: "X9C65hEAAEFIAuLo",
  type: "page",
  tags: [],
  slug: "another-document",
  lang: "en-us",
  uid: "another-document",
  link_type: "Document",
  isBroken: false,
  text : "Click Here"
},

There are two things that you might want to do with a link:

  • Link to another page or media item, internally or externally
  • Pull in content from another document

Here's how to do those two things:

Link to another page

Internal linking always requires a route resolver, which you should have created in the Define Routes step. Here is how to create a link with the link component:

Copy
<!-- With default text property -->
<prismic-link :field="document.data.example_link" />

<!-- Overriding with custom children -->
<prismic-link :field="document.data.example_link">Custom label</prismic-link>

Here is how to create a link with the link helper function:

Copy
<!-- With default text property -->
<router-link :to="$prismic.asLink(document.data.example_link)">
  {{ document.data.example_link.text }}
</router-link>

<!-- Overriding with custom children -->
<router-link :to="$prismic.asLink(document.data.example_link)">
  Custom Label
</router-link>

Pull in content from another document

To pull in content from another content, you must fetch that content in your API Query, using the graphQuery or fetchLinks option. To do so, add an options object to your query, with fetchLinks as a key, and the field that you want to fetch as the value. The field is formatted as [type].[field]:

Copy
<script setup>
const { client } = usePrismic();

const { data: page } = await useAsyncData("page", async () => {
  const page = await client.getByUID("page", "hello-world", {
    fetchLinks: "category.example_key_text",
  });

  if (page) {
    return page;
  } else {
    throw createError({ statusCode: 404, message: "Page not found" });
  }
});
</script>

You can learn more about how to use these options in the @prismicio/client version 5 Technical Reference.

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
// document.data.example_content_relationship
{
  id: "X9C65hEAAEFIAuLo",
  type: "page",
  tags: [],
  slug: "another-page-title",
  lang: "en-us",
  uid: "page-2",
  data: {
    example_key_text: "Another Page's Key Text"
  },
  link_type: "Document",
  isBroken: false,
},

You can then template that content as usual:

Copy
<span>{{ page.data.example_content_relationship.data.example_key_text }}</span>
<!-- <span>Example Linked Key Text</span> -->

Groups

The group field is a repeatable collection of fields. This is useful for a data point that might have multiple instances, such as document categories or authors.

A group field renders an array of content groups:

Copy
// document.data.example_group
[
  {
    example_boolean_in_group: true,
    example_number_in_group: 3,
    example_key_text_in_group: "dog"
  },
  {
    example_boolean_in_group: false,
    example_number_in_group: 7,
    example_key_text_in_group: "cat"
  },
],

To template a group, you can use a v-for:

Copy
<ul>
  <li v-for="item in document.data.example_group" key="item.example_key_text_in_group">
    {{ example_key_text_in_group }} - {{ example_number_in_group }}
  </li>
</ul>

Metadata

An API response also contains metadata for the API response and for the individual result. Here's a truncated example for a standard query of multiple documents, as discussed above:

Copy
{
  // Response metadata
  page: 1,
  results_per_page: 20,
  results_size: 3,
  total_results_size: 3,
  total_pages: 1,
  next_page: null,
  prev_page: null,
  results: [
    {
      // Document metadata
      id: 'YBQvbxUAACUAa5jh',
      uid: 'example-uid',
      type: 'page',
      href: 'https://your-repo-name.cdn.prismic.io/api/v2/documents/sear...',
      tags: [],
      first_publication_date: '2021-01-29T15:53:23+0000',
      last_publication_date: '2021-01-29T15:53:23+0000',
      slugs: ['hello-world'],
      linked_documents: [],
      lang: 'en-us',
      alternate_languages: [],
      data: {
        // Document data
        example_date: '2020-12-10',
        example_timestamp: '2020-12-10T04:05:09+0000',
        // ... More document data
      }
    },
    // ... More documents
  ]
}

The response metadata is often used for more advanced query functions, such as pagination.

The metadata for a single document includes some useful information, such as the document's UID and published date.



Can't find what you're looking for?

Need technical Support? Spot an error in the documentation? Get in touch with us on our Community Forum.