Template Content

On this page, you'll learn how to template content from the Prismic API in your Svelte 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.

Before you proceed

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

Simple field types can be injected directly into your application:

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

@prismicio/helpers includes special utilities for rendering structured fields. To render Rich Text, for instance, you can use asHTML:

Copy
{@html prismicH.asHTML(document.data.example_title)}

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

In fact, 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 make a query using a paginated get method, like get(), you will get a response object, which contains 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,
      }
    },
    {...},
    {...},
    {...}
  ]
}

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 Svelte, 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>
  {#each response.results as document}
    <li>
      { document.data.example_key_text }
    </li>
  {/each}
</ul>

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

The results array

When you make a query using a get-all method, such as getAllByType(), you will get a results array containing all matching results. (If you use a paginated get method, it will contain 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_key_text: 'Example Key Text Value',
    }
  },
  {...},
  {...},
  {...}
]

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 Svelte, you might use that 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 helper functions 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> -->

Simple fields

The content for each Prismic field is delivered as either 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

Prismic fields

You can learn more about all of these fields in our Core Concepts documentation.

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>$74</span> -->

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

Copy
<h3 style="color: {document.data.example_color};">My favorite color is Red</h3>
<!-- <h3 style="color: #FF00000;">My favorite color is Red</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

prismicH.asDate() takes a Date or Timestamp field from Prismic and converts it to a JavaScript date object. To learn more about JavaScript Date objects, see the MDN Date documentation or this tutorial by Tania Rascia.

Both fields are handled the same way:

Copy
<script>
  import * as prismicH from "@prismicio/helpers";
</script>

<p>{prismicH.asDate(document.last_publication_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</time> ->>

GeoPoint

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

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

Here is an example of how to retrieve the latitude & 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

This is the 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 template an Embed field using the html property on the response. To render HTML, use Svelte's @html block. Read more.

Copy
{@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 in an <img> element using the asImageSrc() function.

Copy
<script>
  import * as prismicH from "@prismicio/helpers"
</script>

<img  
  src={prismicH.asImageSrc(document.data.example_image)}
  alt={document.data.example_image.alt} 
/>

Images can be transformed using Prismic’s built-in Imgix integration and asImageSrc(). 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
<script>
  import * as prismicH from "@prismicio/helpers"
</script>

<img  
  src={prismicH.asImageSrc(document.data.example_image, { sat: -100 })}
  alt={document.data.example_image.alt} 
/>

Automatically make your images responsive using asImageWidthSrcSet(), which will generate a set of responsive image URLs:

Copy
<script>
  import * as prismicH from "@prismicio/helpers"
</script>

<img  
  src={prismicH.asImageSrc(document.data.example_image)}
  srcset={prismicH.asImageWidthSrcSet(document.data.example_image).srcset} 
  alt={document.data.example_image.alt} 
/>

Learn more about the Image helper methods in the @prismicio/helpers Technical Reference.

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 HTML

To render the Rich Text and Title field, use the prismicH.asHTML() method. It will convert your Rich Text field to HTML code. Then, you can use Svelte's {@html } utility to render it.

Copy
<script>
  import * as prismicH from "@prismicio/helpers";
</script>

{@html prismicH.asHTML(document.data.example_rich_text)}

Creating an HTML Serializer

To modify the HTML output of a Rich Text, create an HTML Serializer function. The HTML Serializer identifies an element by its type and returns output accordingly. Here is an example of an HTML Serializer that will wrap content with a custom label in <mark> tags.

const htmlSerializer = (type, element, content, children) => {
  if(element.data?.label === "example_label") return `<mark>${children}</mark>`
}

Learn more about HTML Serializer in the Core Concepts guide.

Using your HTML Serializer

To use your HTML Serializer function, pass it as a param to the Rich Text method along with your Rich Text field. Make sure to pass it in as the third parameter — the first being the Rich Text field itself and the second being an optional Link Resolver.

{@html prismicH.asHTML(document.data.rich_text, null, htmlSerializer)}

Output as plain text

The prismicH.asText() method will convert and output the text in the Rich Text or Title field as a string.

Copy
<script>
  import * as prismicH from "@prismicio/helpers";
</script>

{prismicH.asText(document.data.example_rich_text)}

Links and Content Relationships

The Route Resolver

Prismic does not know the routing of your Svelte app. You can tell Prismic the structure of your app with a Route Resolver when you create a client. (You should have already created a Route Resolver when you Installed Prismic in your app.) Prismic will then use that information to add a url property to each document. Alternatively, you can create the URLs yourself with a Link Resolver.

To learn more about creating URLs, see our article on Link Resolving and Route Resolving.

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 what a Content Relationship field looks like from the API (a Link field takes a similar format). This field has an API ID example_content_relationship, and it links to another document that has the UID another-document and the type page.

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

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

Link to web

Here's how to render a link from a Link to Web.

Copy
<script>
  import * as prismicH from "@prismicio/helpers";
</script>

<a href={prismicH.asLink(document.data.example_link)}>Example Link</a>

Pull in data 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 use fetchLinks, the value should be:

  • First, the API ID of the Custom Type is referenced 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 is author_name:

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

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: "John Doe"
  },
  link_type: "Document",
  isBroken: false
},

You can then template that content:

Copy
<strong>By { document.data.example_content_relationship.data.author_name }</strong>
<!-- <strong>By John Doe</strong> -->

Groups

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 fields, use an #each block like this:

Copy
<script>
  import * as prismicH from "@prismicio/helpers";
</script>

<ul>
  {#each document.data.example_group as item}
    <li> 
      <a href={prismicH.asLink(item.example_nav_link)}>
        {item.example_nav_label}
      </a>
    </li>
  {/each}
</ul>

Slices

Slices are repeatable, rearrangeable content sections. Learn more about Slices in What is a Slice?

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 SliceZone. The difference between Groups and Slices is that Groups can only be repeated, while Slices can be repeated and mixed.

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

Copy
body: [
  {
    slice_type: 'text_slice',
    slice_label: null,
    items: [{}],
    primary: {
      rich_text: [
        {
          type: 'paragraph',
          text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
          spans: [],
        },
      ],
    },
  },
  {
    slice_type: 'image_gallery_slice',
    slice_label: null,
    items: [{...}],
    primary: {
      gallery_title: [
        {
          type: 'heading1',
          text: 'Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
          spans: [],
        },
      ],
    },
  },
]

Render slices

To template Slices, iterate over the Slice array and render each Slice by evaluating the slice_type through an if-else or switch block.

In the following example, we have two Slices called text_slice and image_gallery_slice. text_slice only contains a Rich Text field. image_gallery_slice contains a Title field and an array of Images in the repeatable zone.

Copy
<script>
  import * as prismicH from "@prismicio/helpers"
</script>

{#each document.data.body as slice}

  <!-- Render Slices of type `text_slice` -->
  {#if slice.slice_type === "text_slice"} 
    {@html prismicH.asText(slice.primary.rich_text)}

  <!-- Render Slices of type `image_gallery_slice` -->
  {:else if slice.slice_type === "image_gallery_slice"}
  
    <!-- Loop over Slice's repeatable zone, `items` -->
    {#each slice.items as image}
      <img 
        src={image.example_image_field.url}
        alt={image.example_image_field.alt}
      />
    {/each}

    <!-- Render Slice's non-repeatable zone, `primary` -->
    <small>{prismicH.asText(slice.primary.gallery_title)}</small>

  {/if}
{/each}

This is a highly simplified example. More likely, you would create a component for each Slice.


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.