Create Homepage Slices

Welcome to the 3rd article in the Gatsby and Prismic getting started tutorial series. We'll be walking through the steps required to convert the content from the top homepage from hard-coded to use content from Prismic.


🕙  Before Reading

If you haven't already gone through the first step, we recommend you start there to download the project, launch a Prismic repository, and install the required plugin and dependencies.

Content modeling

Run npm start to re-launch your site and look at the homepage. As you can see, we can split the content into components. We want this page's main content to be intuitive so that our content authors can mix and match the page elements to build the homepage. Prismic's Slices will be perfect for this!

The models for these Slices already exist in your Prismic repository. Click on Custom Types, and select the Homepage type to see how the configuration of the Slice Zone.

Then, click the Documents button and select the Homepage to view the live version of the Slices. They should look something like this:

⚠️ No need to modify the Custom Types

You do not need to change anything in the Custom Types of your repository. However, if you wish to change anything, we highly recommend you wait until the end of this step-by-step tutorial and read the dedicated plugin configuration article.

Now that we know how to model Slices let's learn how to add them to your Gatsby project.

1. Test the query

Run the project with npm start. Next, open the GraphQL Playground a thttp://localhost:8000/__graphql and paste this GraphQL query. In this example, we're going to retrieve the Quote Slice in our Custom Type to check that everything is working:

Copy
query MyQuery {
  prismicHomepage {
    data {
      body {
        ... on PrismicHomepageDataBodyQuote {
          slice_type
          primary {
            quote {
              text
            }
          }
        }
      }
    }
  }
}

Run the query by pressing the "play" button ▷ at the top to see the query results on the right. We added new types of fields; let's go over them:

  • Union type ... on: We use it to specify the Slices we want from each document.
  • slice_type: This field will allow us to know which component to render depending on it.
  • The items and primary inside Slices: These represent the repeatable and non-repeatable zones of the Slice. We specify all the fields we need to retrieve using their API IDs and the values required.

Instead of adding this entire query in our page files, we will use fragments to make this tutorial more readable and segmented queries. Thus, each component will have its query. If you want to know more about how the fragments work, read the dedicated section:

2. Render the results

Now that we have our query let's add it to our Homepage. But first, let's create a SliceZone component to handle the Slices logic.

1. Update the index.js file

Navigate to 〜/src/pages/index.js and add the SliceZone from @prismicio/react. This component will render the type of each Slice on the page. The following code will add the SliceZone component to the template, update the query with the fragments for each Slice component, and import the component for each Slice (we'll create these in the next step):

Copy
// index.js file

import * as React from 'react'
import { graphql } from 'gatsby'
import { SliceZone } from '@prismicio/react'

import { Layout } from '../components/Layout'
import { Seo } from '../components/Seo'
import { HomepageBanner } from '../components/HomepageBanner'
import { components } from '../slices'

const HomeTemplate = ({ data }) => {
  if (!data) return null
  const doc = data.prismicHomepage.data

  return (
    <Layout isHomepage>
      <Seo title="Home" />
      <HomepageBanner
        title={doc.banner_title.text}
        description={doc.banner_description.text}
        linkUrl={doc.banner_link.url}
        linkLabel={doc.banner_link_label.text}
        backgroundUrl={doc.banner_background.url}
      />
      <SliceZone slices={doc.body} components={components} />
    </Layout>
  )
}

export const query = graphql`
  query MyQuery {
    prismicHomepage {
      data {
        banner_title {
          text
        }
        banner_description {
          text
        }
        banner_link {
          url
          type
          uid
        }
        banner_link_label {
          text
        }
        banner_background {
          url
        }
        body {
          ... on PrismicSliceType {
            slice_type
          }
          ...HomepageDataBodyText
          ...HomepageDataBodyQuote
          ...HomepageDataBodyFullWidthImage
          ...HomepageDataBodyImageGallery
          ...HomepageDataBodyImageHighlight
        }
      }
    }
  }
`

export default HomeTemplate

Those with sharp eyes might have noticed that we removed the MainContent component. That was the hard-coded content for our homepage, and we no longer need it. Remove it from your index.js, and feel free to remove it from your project files.

2. Create the Slice components

Create a new folder in the 〜/src/slices directory. In the new slices folder, create the following files:

  • Index.js (this one will gather all our components)

Then, the Slices:

  • FullWidthImage.js
  • ImageGallery.js
  • ImageHighlight.js
  • Quote.js
  • Text.js

Now, paste the following code into your new files:

  • index.js
  • FullWidthImage.js
  • ImageGallery.js
  • ImageHighlight.js
  • Quote.js
  • Text.js
Copy
import { FullWidthImage } from './FullWidthImage'
import { ImageGallery } from './ImageGallery'
import { ImageHighlight } from './ImageHighlight'
import { Quote } from './Quote'
import { Text } from './Text'

export const components = {
  full_width_image: FullWidthImage,
  image_gallery: ImageGallery,
  image_highlight: ImageHighlight,
  quote: Quote,
  text: Text,
}
Copy
// FullWidthImage.js file

import * as React from 'react'
import { graphql } from 'gatsby'

export const FullWidthImage = ({ slice }) => (
  <section className="full-width-image content-section">
    <img
      src={slice.primary.full_width_image.url}
      alt={slice.primary.full_width_image.alt}
    />
  </section>
)

export const query = graphql`
  fragment PageDataBodyFullWidthImage on PrismicPageDataBodyFullWidthImage {
    primary {
      full_width_image {
        url
      }
    }
  }
  fragment HomepageDataBodyFullWidthImage on PrismicHomepageDataBodyFullWidthImage {
    primary {
      full_width_image {
        url
      }
    }
  }
`
Copy
import * as React from 'react'
import { graphql } from 'gatsby'
import { PrismicLink, PrismicRichText } from '@prismicio/react'

export const ImageGallery = ({ slice }) => {
  return (
    <section className="image-gallery content-section">
      <PrismicRichText field={slice.primary.gallery_title.richText} />
      <div className="gallery">
        {slice.items.map((galleryItem, index) => (
          <div className="gallery-item" key={`gallery-item=${index}`}>
            <img src={galleryItem.image.url} alt={galleryItem.image.alt} />
            <PrismicRichText field={galleryItem.image_description.richText} />
            <p className="gallery-link">
              <PrismicLink href={galleryItem.link.url}>
                {galleryItem.link_label.text}
              </PrismicLink>
            </p>
          </div>
        ))}
      </div>
    </section>
  )
}

export const query = graphql`
  fragment PageDataBodyImageGallery on PrismicPageDataBodyImageGallery {
    primary {
      gallery_title {
        richText
      }
    }
    items {
      image {
        url
        alt
      }
      image_description {
        richText
      }
      link {
        url
        type
        uid
      }
      link_label {
        text
      }
    }
  }
  fragment HomepageDataBodyImageGallery on PrismicHomepageDataBodyImageGallery {
    primary {
      gallery_title {
        richText
      }
    }
    items {
      image {
        url
        alt
      }
      image_description {
        richText
      }
      link {
        url
        type
        uid
      }
      link_label {
        text
      }
    }
  }
`
Copy
import * as React from 'react'
import { graphql } from 'gatsby'
import { PrismicLink, PrismicRichText } from '@prismicio/react'

export const ImageHighlight = ({ slice }) => (
  <section className="highlight content-section">
    <div className="highlight-left">
      <PrismicRichText field={slice.primary.title.richText} />
      <PrismicRichText field={slice.primary.description.richText} />
      <p>
        <PrismicLink href={slice.primary.link.url}>
          {slice.primary.link_label.text}
        </PrismicLink>
      </p>
    </div>
    <div className="highlight-right">
      <img
        src={slice.primary.featured_image.url}
        alt={slice.primary.featured_image.alt}
      />
    </div>
  </section>
)

export const query = graphql`
  fragment PageDataBodyImageHighlight on PrismicPageDataBodyImageHighlight {
    primary {
      featured_image {
        url
        alt
      }
      title {
        richText
      }
      description {
        richText
      }
      link {
        url
        type
        uid
      }
      link_label {
        text
      }
    }
  }
  fragment HomepageDataBodyImageHighlight on PrismicHomepageDataBodyImageHighlight {
    primary {
      featured_image {
        url
        alt
      }
      title {
        richText
      }
      description {
        richText
      }
      link {
        url
        type
        uid
      }
      link_label {
        text
      }
    }
  }
`
Copy
import * as React from 'react'
import { graphql } from 'gatsby'

export const Quote = ({ slice }) => (
  <section className="content-section quote">
    <blockquote>{slice.primary.quote.text}</blockquote>
  </section>
)

export const query = graphql`
  fragment PageDataBodyQuote on PrismicPageDataBodyQuote {
    primary {
      quote {
        text
      }
    }
  }
  fragment HomepageDataBodyQuote on PrismicHomepageDataBodyQuote {
    primary {
      quote {
        text
      }
    }
  }
`
Copy
import * as React from 'react'
import { graphql } from 'gatsby'
import { PrismicRichText } from '@prismicio/react'

export const Text = ({ slice }) => {
  const columnClass =
    slice.primary.columns === '2 Columns'
      ? 'text-section-2col'
      : 'text-section-1col'

  return (
    <section className={`content-section ${columnClass}`}>
      <PrismicRichText field={slice.primary.content.richText} />
    </section>
  )
}

export const query = graphql`
  fragment PageDataBodyText on PrismicPageDataBodyText {
    primary {
      columns
      content {
        richText
      }
    }
  }
  fragment HomepageDataBodyText on PrismicHomepageDataBodyText {
    primary {
      columns
      content {
        richText
      }
    }
  }
`

Each query component has two almost identical fragment queries. The only difference is the Custom type name, Homepage, and Page in these cases. These fragments help us share the Slices and their components between Custom Types.

3. Test the new content

To test that the content is coming from Prismic, do the following:

  1. First, go to your Prismic repository and open the homepage document.
  2. Make a change to some of your Slices content.
  3. Save and Publish your changes.
  4. Stop the current Gatsby server in your terminal by pressing Ctrl + C.
  5. Relaunch your server by running npm start.

This will re-build your site and update the content from your Prismic repository. You can refresh the homepage when the build is complete and see your updated content.

Next steps

Next up, we will be updating the project to have the content pages built dynamically from Prismic.


Was this article helpful?
Not really
Yes, Thanks

Can't find what you're looking for? Get in touch with us on our Community Forum.