[D8] Responsive Paragraphs with Materialize

Materialize Responsive Paragraphs

Handing Content in Drupal

Drupal does a great job when it comes to creating structured content that has the same layout every time. If we want a list of employee bios, or a grid of products, the combination of Drupal's content types and views are the perfect solution. But when we want to create less structured content like blog posts or articles, the old "Drupal way" breaks down.

In the past we've solved this in one of two ways. We've either given users free reign with the less-than-perfect WYSIWYG approach, or create one-off pages whenever someone wants something a little bit different. This gets to be unmaintainable pretty quickly. But there's now another way to do this. Let me show you how.

The Problem

Let's lay out the individual problems we're trying to solve. In this case, there's two major problems. We want our content entry to be flexible, but the resulting display needs to still fit the aesthetics of the site while also being responsive. It's what website visitors expect, especially now that the number of visitors from mobile devices are increasing. This isn't a problem that can be solved by just a front-end or back-end solution -- it's going to require a bit of both. With this in mind, let's start off with the back-end.

Drupal Content Entry

Content entry in Drupal has always followed a certain style that I like to refer to as "Mad Libs" content entry. We have a front-end template, and we use a form on the back end to fill in the missing content. It looks a little bit like this:

Content Type Example 2

We fill out the different fields in the node creation form, and those values get plugged into the right spots on the resulting web page. Like I alluded to before, this works great when it comes to content that looks the same every time (think of a list of staff bios or event listings). 

The problem arises when we want to create less structured content, like blog posts or articles. A strict structure now becomes limiting. The popular solution used to be to give the content entry person access to a WYSIWYG field. This allowed them a much more flexible way to enter content. Unfortunately it tended to give *too* much control over the end result, which culminated in what I affectionately called the "bake sale" web pages. You know what I'm talking about: six fonts, five colors, and full-sized images. All of which you were supposed to make "look nice" while keeping it responsive. Yikes.

The WYSIWYG editor is fantastic for creating documents (just look at what you can create with Microsoft Word). Unfortunately, the web is no longer a collection of static documents. We need a different way of creating content.

Introducing Paragraphs

The Paragraphs module intends to fix this problem. It works like this: instead of creating fieldable content types, we create fieldable paragraphs. These paragraphs become components of a web page. As a simplistic example, you might have a Text paragraph and an Image paragraph. When you go to create a piece of content, you can add a new paragraph (either text or image) as many times as you want, and in any order you want. And from the site builder side of things, each of these components can be separately themed to give a specific look and feel to each piece. 

Paragraphs Example 2

I know, pretty fancy, huh? Now that we have a new, web-friendlier content entry system, we need to worry about the front-end side of things. So let me introduce you to the idea of the grid.

The Grid

Grid layouts are a way to build responsive front end CSS/JS frameworks. The idea behind the grid is that there is a stack of rows broken out into a number of equal-width columns (12 columns is a popular number), kind of like a spreadsheet. Just like in your spreadsheet software, you can combine columns to create bigger pieces of content in a row. These column widths can be determined based on screen size, which allows the content to take up different widths on different devices. 

The front end framework that we're going to use is called Materialize. It's similar to Bootstrap, but the creators have implemented Google's Material Design aspects into it. They have a great in-depth writeup on their website about the grid system (it's where I got the following images), so I won't go rewriting what they've put together. I will try to summarize it a bit though. Starting with a good visual representation of a responsive grid layout.

Grid Layout Example

As you can see, we have multiple rows of content, differentiated here by the various colors. The first row has a full, 12-column piece of content. The second row has 3 different sized pieces of content. And the third row has 4 equal sized pieces of content. 

The letters in the content blocks ("s12" for example) denote the responsive nature of each block. In this particular grid system (like many of the other ones out there), content is built from a mobile perspective first. The s/m/l denote the screen size (small/medium/large, which is figured out by JavaScript), and the number represents how many columns the content will span for that screen size. 

Let's use the middle row from the above image as an example. Each block starts with s12, which means on small devices (eg. smartphones) each block will be on its own separate row. On medium sized devices (like a tablet) each block will take up 4 of the 12 columns, so the result will be three equal blocks on the same row. And on large devices (like a desktop computer) the outside blocks will take up 2 columns each, while the middle one will take up the remaining 8 columns. Pretty clever, huh?

The best part about this? It's already built in to these front end frameworks like Bootstrap (or the aforementioned Materialize). So all we need to do is add these classes to our HTML and we're up and running as a responsive website. 

Create the Theme

So the first thing we need to do is to create a Drupal theme. I won't go into a lot of detail about how to create a theme in Drupal 8, because drupal.org has already done that. But once you have your theme set up, download your frontend framework of choice and drop the files into your theme folder. Then use the aforementioned guide to hook up any JS and CSS files that you need.

Connecting the Dots: Create Some Paragraphs

So let's talk about how to connect these two ideas together. The first thing we're going to need is some Paragraphs. We can split these into two different categories.

Layout Paragraphs

  • Full Width Row
  • Two Column Row
  • Three Column Row
  • Four Column Row
  • Six Column Row
  • (Parallax Row)

Content Paragraphs

  • Card
  • Code
  • Image
  • Text
  • Accordion

The secret is this: first, create the content Paragraphs. I've made ones that line up with some of the components included in the Materialize framework (like Cards).

Next, create the layout Paragraphs. Inside each Paragraph, add a field for each column in that layout (so the Four Column Row would have 4 column fields). Each field is set to an Entity Reference, so that other Paragraphs can be added to the field. Like this:

Four Column Paragraph Fields

For each of these Paragraph fields, you can add any of the Content Paragraphs we created earlier. The best part about doing it this way is that we can limit which content components we want in each column. For instance, the code component that you see below? You're not going to want that in a 6 column layout because it would be illegible.

This is what I meant when I was talking about giving flexibility, but only to a point. Content Editors can still create flexible content, but Site Builders can still have some control over making sure all the content still fits the look and feel of the site's theme.

Embedded Paragraphs

The last thing we need to do is add the Materialize styles to each of our Paragraph types. Some of you may be eyeing the code below with some trepidation, but I promise this is easier than it may look.

Template Time!

Here's another secret: the templates that we need have already been built. Go to the Paragraphs module folder, and inside will be a templates folder. Inside that you'll find a file called paragraph.html.twig. You can copy this into your theme's templates folder (create it if it doesn't exist) and rename the file to include the machine name of the Paragraph you want to style. For example, my 4 column paragraph is named 4_columns, so I've renamed my template file paragraphs--4-columns.html.twig.

From here you can add your HTML and styles to the code surrounding your content.

  1. {%
  2. set classes = [
  3. 'paragraph',
  4. 'paragraph--type--' ~ paragraph.bundle|clean_class,
  5. view_mode ? 'paragraph--view-mode--' ~ view_mode|clean_class,
  6. 'row',
  7. 'container',
  8. ]
  9. %}
  10. <div class="section">
  11. <div{{ attributes.addClass(classes) }}>
  12. <div class="col s12 m6 l3"> {{ content.field_first_column_4 }} </div>
  13. <div class="col s12 m6 l3"> {{ content.field_second_column_4 }} </div>
  14. <div class="col s12 m6 l3"> {{ content.field_third_column_4 }} </div>
  15. <div class="col s12 m6 l3"> {{ content.field_fourth_column_4 }} </div>
  16. </div>
  17. </div>

Rinse and repeat for all of your different paragraph types, and you'll be looking good in no time! And in case you were wondering whether this works or not, I've built this site using this method, and this blog post is made using these responsive paragraphs! Give it a try by resizing your browser, and you'll see that it's fully responsive.

If you want to see more examples of what this approach can do, check out the demo page I put together.