Create More Components

Beta

These docs rely on Slice Machine, which is in active development and subject to change. Content Relationships are not currently supported with Slices.

This article will reinforce the concepts of breaking a website into blocks, creating Slices, and developing components with Prismic. You'll also learn about the field settings, the repeatable zone, and global styles.


1. Break the Design into Pieces.

So now that you have created a first component for the banner, we'll look at doing the same with the remaining blocks from the homepage. So first let's look at the video below to see how we should divide up these blocks.

From the video above you can see that we have 5 blocks that we will recreate as Slices and components.

  • Full width image
  • Image Gallery
  • Featured Image
  • Quote
  • Text

Below we'll take you through the process of creating each Slice.

2. The full-width Image Slice

So we once more run the prismic sm --create-slice command and give the Slice the name FullWidthImage.

Field settings

In the Slice Builder, delete the existing fields and add an image field with the name (API ID) of image. Then in the field settings ⚙️, we set the restraints on the image: max-width of 980px and max height of 300px. Save the model to the filesystem.

Add Fields Example Video

Component Code

We're going to use the suggested code and paste it into the index.js file. Below is the full component code:

Copy
import React from 'react';

const FullWidthImage = ({ slice }) => (
  <section className="container">
    <img src={slice.primary.image.url} alt={slice.primary.image.alt} />
  </section>
);

export default FullWidthImage;

Global CSS Styles

You can see from the code above that we've added the class called container to the section HTML tag. We added it here but we defined the style for this class globally so that we can use it in any components that need it, you can find the globals.css file in the project directory at ../styles/globals.css. We import this file in the ../pages/_app.js file so that it's used everywhere.

You can see the full CSS of this file and the class we added below (In the 2nd tab, you'll see the full global CSS):

  • CSS Class
  • ../styles/globals.css
Copy
.container {
  max-width: 980px;
  margin: auto;
  margin-bottom: 3.75rem;
}
Copy
* {
  -webkit-font-smoothing: antialiased;
}

*,
*::before,
*::after {
  box-sizing: content-box;
}

::selection {
  background: #fff7c7; /* WebKit/Blink Browsers */
}
::-moz-selection {
  background: #fff7c7; /* Gecko Browsers */
}

/*
 * Globals
 */
body {
  color: #72767b;
  font-family: "Lato", sans-serif;
  font-size: 16px;
  font-weight: 400;
  letter-spacing: 0.4px;
  line-height: 28px;
  margin: 0;
}
a {
  color: #72767b;
  font-size: 14px;
  font-weight: 400;
  letter-spacing: 0.35px;
  line-height: 28px;
  text-decoration: none;
}
p a {
  text-decoration: underline;
}
h2,
h3,
h4,
h5,
h6 {
  font-family: "Lato", sans-serif;
}
h1 {
  font-size: 42px;
  font-weight: normal;
  color: #484d52;
  line-height: 52px;
  letter-spacing: 1.14px;
  margin-bottom: 1rem;
}
h2,
h2 a {
  margin-bottom: 1rem;
  color: #484d52;
  font-size: 32px;
  font-weight: 700;
  letter-spacing: 0.85px;
  line-height: 42px;
}
h3,
h3 a {
  margin-bottom: 1rem;
  color: #484d52;
  font-size: 20px;
  font-weight: 400;
  letter-spacing: 0.52px;
  line-height: 34px;
}
p,
pre,
ul,
ol {
  margin-bottom: 2rem;
}
ul {
  padding-left: 35px;
  list-style: initial;
}
ol {
  padding-left: 35px;
  list-style: decimal;
}
strong {
  font-weight: bold;
}
em {
  font-style: italic;
}
img {
  max-width: 100%;
}

/* General */
header,
footer {
  max-width: 980px;
  margin: auto;
}
.container {
  max-width: 980px;
  margin: auto;
  margin-bottom: 3.75rem;
}

@media (max-width: 767px) {
  h1 {
    font-size: 32px;
    line-height: 40px;
  }
  h2 {
    font-size: 26px;
  }
  h3 {
    font-size: 18px;
  }
  ul {
    padding-left: 20px;
  }
}

Using Global CSS with Storybook

To use Global CSS files like this with the Storybook (The local component development environment) you need to declare it in the Storybook settings file located ../.storybook/main.js. Here you'll need to add the path to your CSS file, you can see what this file should look like with the path to your CSS below.

Copy
module.exports = {
  stories: ["../slices/**/*.stories.[tj]s", "../styles/globals.css"]
}

Once this is done you can check out your full width image component in Storybook and Push the Slice in the the Slice Builder.


3. The Image Gallery Slice

The Repeatable Zone

In this Slice we will use the repeatable zone in the Slice Builder. The repeatable zone allows you to have multiple iterations of a group of fields within a Slice. This gives your content creators the power to add content for things like galleries, sliders, etc.

Below you can see the fields we'll need and in which zones.

Non-repeatable zone

galleryTitle

Rich Text field, with only the H2 option selected

Repeatable zone

image

Image field, with a max width of 727px & a max height of 402px

imageDescription

Rich Text field

link

Link field

linkLabel

Key Text field

Add Fields Example video

Component Code

You'll see when creating your Slice that the suggested code snippets for the fields in the repeatable zone come wrapped in a map array method, so the fields will repeat for each item in the group.

In this example, we're going to use one loop for all fields from the repeatable zone as shown in the full component code and JSX Style below.

Once this is added, refresh the preview image and push your Slice to Prismic.

Copy
import React from 'react'
import { RichText } from 'prismic-reactjs'
import { Link } from 'prismic-reactjs'

const ImageGallery = ({ slice }) => (
  <section className="image-gallery container">
    <RichText render={slice.primary.galleryTitle} />
    <div className="gallery">
      { slice?.items?.map((item, i) =>
        <div key={i} className="gallery-item">
          <img
            src={item.image.url}
            alt={item.image.alt}
          />
          <RichText render={item.imageDescription}/>
          <p>
            <a className="gallery-link" href={Link.url(item.link)}>
              <span>{item.linkLabel}</span>
            </a>
          </p>
        </div>
      )}
    </div>
    <style jsx>{
      `
      .image-gallery {
        margin-bottom: 3.75rem;
        padding: 20px;
        color: #72767b;
        font-family: 'Lato', sans-serif;
        font-size: 16px;
        font-weight: 400;
        letter-spacing: 0.4;
        line-height: 28px;
      }
      .gallery {
        display: -webkit-box;  /* OLD - iOS 6-, Safari 3.1-6, BB7 */
        display: -ms-flexbox;  /* TWEENER - IE 10 */
        display: -webkit-flex; /* NEW - Safari 6.1+. iOS 7.1+, BB10 */
        display: flex;
        -webkit-flex-wrap: wrap;
        flex-wrap: wrap;
        -webkit-justify-content: space-between; 
        justify-content: space-between; 
      }
      .gallery-item {
        -webkit-box-flex: 0 1 48%;
        -moz-box-flex:  0 1 48%;
        -webkit-flex:  0 1 48%;
        -ms-flex:  0 1 48%;
        flex: 0 1 48%;
      }
      .gallery-link {
        margin-top: -20px;
        text-transform: uppercase;
      }
      .gallery img {
        margin-bottom: 1rem;
      }
      @media (max-width: 767px) {
        .image-gallery {
          margin-bottom: 2rem;
        }
        .gallery-item {
          -webkit-box-flex: 100%;
          -moz-box-flex:  100%;
          -webkit-flex:  100%;
          -ms-flex:  100%;
          flex: 100%;
        }
      }
      `
    }</style>
  </section>
)

export default ImageGallery

4. Featured Image

Again, run the prismic sm --create-slice command to create a FeaturedImage slice, and add the following fields in the Slice Builder.

Fields to add

title

Rich text field, with only the H2 option selected.

headline

Rich text field, with only the H3 option selected.

link

Link field

linkLabel

Key text field

featuredImage

Image field, with a max width of 727px & a max height of 402px

Component Code

Here's the full component code & styled-components. Copy this code into the file ~/slices/FeaturedImage/index.js and save it. Then, go back to the Slice Builder, refresh the preview image and push your Slice to Prismic. In this example, we've used CSS grid to create our columns.

Copy
import React from 'react'
import { RichText } from 'prismic-reactjs'
import { Link } from 'prismic-reactjs'

const FeaturedImage = ({ slice }) => (
  <section className="highlight container">
    <div>
      <RichText render={slice.primary.title} />
      <RichText render={slice.primary.headline} />
      <p>
        <a href={Link.url(slice.primary.link)}>
          <span>{slice.primary.linkLabel}</span>
        </a>
      </p>
    </div>
    <div>
      <img
        src={slice.primary.featuredImage.url}
        alt={slice.primary.featuredImage.alt}
      />
    </div>
    <style jsx>{`
      .highlight {
        display: grid;
        grid-template-columns: 1fr 1fr;
        column-gap: 25px;
      }
      @media (max-width: 767px) {
        .highlight {
          grid-template-columns: 1fr;
        }
      }
      `}</style>
  </section>
)

export default FeaturedImage

5. Quote Slice

This one is pretty simple. Run the prismic sm --create-slice command, create a QuoteSlice and add the following field in the Slice Builder.

Fields to add

quotetext

Rich text field with only the p option for paragraphs selected.

This time instead of using the suggested code we'll use the asText method to print our quote to strip away any extra formatting and take more control of the output so all our quotes look consistent.

Component Code

Here's the full component code & style:

Copy
import React from 'react'
import { RichText } from 'prismic-reactjs'

const QuoteSlice = ({ slice }) => (
  <section className="container quote">
    <blockquote>
      {RichText.asText(slice.primary.quotetext)}
    </blockquote>
    <style jsx>{`
      .quote blockquote {
        display: block;
        font-family: 'Lora', Serif; 
        font-size: 36px;
        font-style: italic;
        font-weight: normal; 
        color: #484D52; 
        letter-spacing : 1.14;
        line-height: 1.5em;
        text-align: center;
      }
      .quote blockquote:before,
      .quote blockquote:after {
        color: #e9e9e9;
        content: open-quote;
        font-family: 'Lora', Serif;
        font-size: 2.5em;
        font-weight: 900;
        line-height: 0.1em;
        margin-left: 10px;
        margin-right: 10px;
        vertical-align: -0.3em;
      }
      .quote blockquote:after {
        content: close-quote;
      }
      @media (max-width: 767px) {
        .quote {
          font-size: 20px;
        }
      }
    `}</style>
  </section>
)

export default QuoteSlice

6. Text Slice

Finally, run the prismic sm --create-slice command and create a TextSlice. In the Slice Builder, add the following field.

text

Rich text field

Component Code

Finally, the simplest Slice to create is the Text slice. Again run the prismic sm --create-slice command and in the Slice Builder add a Rich text field with the API ID text. This is just a plain text block with all options for the content writers to use as they see fit. So there's no extra style to add in the component, as seen below.

Copy
import React from 'react';
import { RichText } from 'prismic-reactjs';

const TextSlice = ({ slice }) => (
  <section className="container">
    <RichText render={slice.primary.text} />
  </section>
);

export default TextSlice;

Congratulations! You've now created all the components and Slices that you'll need for you website. Next we're going to learn how to see these components with live data from our CMS.


Next and previous articles


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.