Convert Everything to 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 in to 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.

Now you know how to create a website block as a component with Nuxt.js and Prismic we'll look at doing the same with the remaining blocks from the homepage. First, let's look at 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 this process for each Slice.

2. The 'Full Width Image' Slice

Again we click the + button to create a new Slice and then give the Slice the name FullWidthImage. We then delete the existing fields and add an image field with the name (API ID) of image.

Field settings

Then in the field settings ⚙️, we set the restraints on the image to a max-width of 980px and max height of 300px.

Component code

After that, we copy the suggested code and paste it into the index.vue file for the FullWidthImage component. Below is the full component code.

Copy
<template>
  <section class='content-section container'>
    <prismic-image :field="slice.primary.image"/>
  </section>
</template>

<script>
export default {
  props: {
    slice: {
      type: Object,
      required: true,
      default() {
        return {}
      },
    },
  },
}
</script>

<style scoped>
@media (max-width: 767px) {
  .content-section {
    margin-bottom: 2rem;
  }
}
</style>

Global CSS

You can see from the code above we've added the class container. We called it here but we defined this CSS class globally so that we can use it in all our components that need it. We specified where this global CSS file lives in the nuxt.config.js file and give the container the following style. You'll also find the full global styles to include, like titles and links, in the 3rd tab below:

  • CSS
  • nuxt.config.js
  • Full Global CSS
Copy
.container {
  max-width: 980px;
  margin: auto;
}
Copy
  css: [
    "vue-essential-slices/src/styles/styles.scss",
    '@/assets/css/global.css',
  ],
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;
}
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 */
.container,
header,
footer {
  max-width: 980px;
  margin: auto;
}
.content-section {
  clear: both;
  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;
  }
}

Once this is done you can check out your full width image component in Storybook and Push the Slice in 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

An image field with a max width of 727px & a max height of 402px (image)

imageDescription

A Rich text field. (imageDescription)

link

Link field (link)

linkLabel

Key text field (linkLabel)

Add fields example video

Full 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 v-for loop. This is for the fields to be repeated whatever number of times the content writers use the group. For our example we need to combine all the fields from the repeatable zone in to one for loop as shown in the full component code & scoped style below.

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

Copy
<template>
  <section class='image-gallery content-section container'>
    <prismic-rich-text :field="slice.primary.galleryTitle"/>
    <div class="gallery">
      <div v-for="(item, i) in slice.items" :key="`slice-item-${i}`" class="gallery-item">
        <prismic-image :field="item.image"/>
        <prismic-rich-text :field="item.imageDescription"/>
        <p>
          <prismic-link :field="item.link" class="gallery-link">{{ item.linkLabel }}</prismic-link>
        </p>
      </div>
    </div>
  </section>
</template>
<script>
export default {
  props: {
    slice: {
      type: Object,
      required: true,
      default() {
        return {}
      }
    }
  },
}
</script>
<style scoped>
.gallery {
  display: -webkit-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  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;
}

@media (max-width: 767px) {
  .content-section {
    margin-bottom: 2rem;
  }

  .gallery-item {
    -webkit-box-flex: 100%;
    -moz-box-flex: 100%;
    -webkit-flex: 100%;
    -ms-flex: 100%;
    flex: 100%;
  }
}
</style>

4. 'Featured Image' Slice

Again, press the + button to create a FeaturedImage slice, and add the following fields in the Slice Builder.

Fields to add

Title

A Rich text field with only the H2 option selected. (title)

Headline

A Rich text field with only the H3 option selected. (headline)

Link

Link field

Label

Key text field (linkLabel)

Image

Image field with a max width of 727px & a max height of 402px (featuredImage)

Component code

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

Copy
<template>
  <section class='highlight content-section container'>
    <div>
      <prismic-rich-text :field="slice.primary.title"/>
      <prismic-rich-text :field="slice.primary.headline"/>
      <prismic-link :field="slice.primary.link">{{ slice.primary.linkLabel }}</prismic-link>
    </div>
    <div>
      <prismic-image :field="slice.primary.featuredImage"/>
    </div>
  </section>
</template>

<script>
export default {
  props: {
    slice: {
      type: Object,
      required: true,
      default() {
        return {}
      },
    },
  },
}
</script>

<style scoped>
.highlight {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 25px;
}
@media (max-width: 767px) {
  .highlight {
    grid-template-columns: 1fr;
  }
}
</style>

5. Text Slice

Now, we're going to create a text block that can be either 1 or 2 columns called TextSlice. First, in the Slice Builder, add the following field.

text

Rich Text field

To give our content creators the ability to choose between options (1 or 2 columns), we use the 'Variations' feature. To create a variation select the dropdown on the top of the Builder and click the '+ Add new variation' option.

The '+ Add new variation' button.
The '+ Add new variation' button.

The 'Add new variation' screen has 3 options:

  • Variation Name: This is the label that you will see in the Builder and your Prismic documents.
  • Variation ID: This is the API ID in the Slice Model which can be used in your component to create variations.
  • Duplicate from: Here you select which of the existing variations you wish to base your new variation on.

We will call our Variation 'Two Column; which creates the ID twoColumn and we'll duplicate it from the default Slice.

The 'Add new variation' screen.
The 'Add new variation' screen.

Component code

In the component code, use the field slice.variation from the Slice model to create the difference in the component. For this example, we use it as a class name by which to change the column count of the text block. Save, then check Storybook to see the Variations with mock content.

Copy
<template>
  <section :class="`content-section container ${ slice.variation }`">
    <prismic-rich-text :field="slice.primary.text"/>
  </section>
</template>

<script>
export default {
  props: {
    slice: {
      type: Object,
      required: true,
      default() {
        return {}
      },
    },
  },
}
</script>

<style scoped>
.default-slice {
  column-count: 1;
}
.twoColumn {
  column-count: 2;
}
</style>

Preview your 'Variations'

You can then head over to Storybook to check out how your variations will differ.

Pro Tip: Edit your Mock Config for the text field in the Prismic Builder to add more text block to really show the difference between your variations.


6. Quote Slice

For this 'Quote' Slice we're are also going to add a variation, we're going to give the content creators the option to add a reference to the quote that they use. To make the Slice click the 'Create Slice +' button, create a QuoteSlice and add a quotetext rich text field in the Builder.

Then to create a variation select the dropdown on the top of the Builder and click the '+ Add new variation' option, call it 'Quote Reference' which will give you an API ID of quoteReference for the variation. Then in this variation add another Rich Text field called reference. All of these fields are described below:

Fields to add

quotetext

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

reference (Variation)

Rich text field with only the p, bold, italic and link options for paragraphs selected.

Add variation example video:

This time instead of using the suggested code for the quotetext field 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. Then for the reference field we'll conditionally render it if the content creator chooses the quoteReference variation.

Component code

Here's the full component code & style:

Copy
<template>
  <section class='content-section quote container'>
    <blockquote class="block-quotation">
      {{ $prismic.asText(slice.primary.quotetext) }}
    </blockquote>
    <div v-if="slice.variation === 'quoteReference'">
      <cite>
        <prismic-rich-text :field="slice.primary.reference" />
      </cite>
    </div>
  </section>
</template>

<script>
export default {
  props: {
    slice: {
      type: Object,
      required: true,
      default() {
        return {}
      },
    },
  },
}
</script>

<style scoped>
.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;
  quotes: "“" "”" "‘" "’";
  text-align: center;
  margin-bottom: 12px;
}
.quote blockquote:before {
  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 {
  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;
  content: close-quote;
}
.quote div {
  width: 300px;
  float: right;
}
.quote div cite {
  display: flex;
  line-height: 18px;
}
.quote div cite:before {
  content: '-';
  margin: 0px 4px 0px 0px;
}
@media (max-width: 767px) {
  .content-section {
    margin-bottom: 2rem;
  }

  .quote {
    font-size: 20px;
  }
}
</style>

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.