Four Kitchens
Insights

Building with Emulsify part 4: Component grid

6 Min. ReadDesign and UX

Now that we have set up our style guide, built a simple component, and dealt with a couple of common component complexities, we can now move on to the final important piece of the component-driven puzzle: the grid. Or, to use Atomic Design language, “the organism level” (and beyond). For our purposes, let’s look at this grid of cards based on our last article:

Emulsify 3-card grid

Here we have a card grid that is 3 across at a large screen size. We don’t need much in the way of markup for this — just a wrapper element for some basic flexbox styling. In fact, as you’ll soon find out, creating a grid/row organism is pretty simple, but there are a few key ingredients to learn in the process.

Card Grid component

For our Card Grid component, let’s create the following new component files in the components > organisms directory:

card-gridrn_card-grid.scssrncard-grid.twigrncard-grid.yml

Card Grid markup

For our markup, let’s write the following in our Twig file:

{% extends "@organisms/grid/grid.twig" %}

{% block grid_content %}
  {% for card in cards %}
    {% include "@molecules/card/card.twig" with {rn      card_title: card.card_title,rn      card_body: card.card_body,rn      card_link_text: card.card_link_text,rn      card_link_url: card.card_link_url,rn    } %}
  {% endfor %}
{% endblock %}

Notice the use of extends here. We haven’t covered this yet, and this is the first trick you’ll want to learn as you scale to organisms and beyond. Twig’s extends tag (and its more powerful cousin, the embed tag, which we’ll discuss in a moment) prints the markup from the file referenced just like the include function we’ve covered before, but also allows you to populate something called Twig blocks—where their true power lies. Meaning, in the original file, you can define Twig blocks for sections that you want to replace in another file. Let’s look at the original grid file referenced here paying special attention to {% block grid_content %} and {% endblock %}:

{% set grid_base_class = grid_base_class|default('grid') %}

..

<div {{ bem(grid_base_class, (grid_modifiers), grid_blockname) }}>
  {% block grid_content %}
    {% for item in items %}
      <div class="grid__item">{{ item }}</div>
    {% endfor %}
  {% endblock %}
</div>

Here, the outer <div> element will always be printed, but the Twig block grid_content defines a section that can be replaced completely when using extends or embed. So, in our card grid component above, the contents inside of {% block grid_content %} ({% for card in cards %})will completely replace the parts defined in the original file ({% for item in items %})

Card Grid markup

Now, let’s populate the cards loop for Storybook by looping through some sample data in our card-grid.yml file like so:

cards:
 - card_modifiers:
     - "grid-item" 
    card_title: "This is a card title" 
    card_link_text: "Button Link Text" 
    card_link_url: "#" 
    card_body: "Curabitur non nulla sit amet nisl tempus convallis quis ac lectus." 
  - card_modifiers:
     - "grid-item" 
    card_title: "Vivamus Magna Justo" 
    card_link_text: "Button Link Text" 
    card_link_url: "#" 
    card_body: "Curabitur non nulla sit amet nisl tempus convallis quis ac lectus. Vivamus magna justo, lacinia eget consectetur sed" 
  - card_modifiers:
     - "grid-item" 
    card_title: " Donec Rutrum Congue Leo Eget Malesuada" 
    card_link_text: "Button Link Text" 
    card_link_url: "#" 
    card_body: "Curabitur non nulla sit amet nisl tempus convallis quis ac lectus. Vivamus magna justo, lacinia eget consectetur sed, convallis at tellus."

Here we are providing a “cards” array (which is why our component loop supplies data with syntax like card.card_title). Now that we have walked through this helpful exercise, you should also know Emulsify provides a number of grid examples, including a card grid example, right out of the box

And now that we have our markup and data, we’re ready to move onto style our card grid. We haven’t covered styling too much because it is mostly straightforward CSS/SCSS, but there is something worth noting here about Emulsify

Styling usage

If you have explored styling and the Sass usage in Emulsify, you may have noticed that simply using the grid class can work to stylize your rows horizontally like in the picture above. But that is not the intended usage. The intention is that you use the same approach taken in the _grid.scss approach, which is to utilize the mixin. With that in mind, the only CSS we need in _card-grid.scss is as follows:

.card__grid {rn  @include grid;
}

.cardu002du002dgrid-item {rn  @include grid-item(3);
}

That’s it! This will create a grid that will be 3 across for larger screens. All that is left now is to add your component to Storybook and you can use our example in the second article or the default grid examples in Emulsify to see how that is accomplished. Let’s move on to the Drupal integration to finish our tutorial.

Drupal Grid

Let’s say our grid in Drupal will be a paragraph called “Card Grid.” This paragraph will contain a single multi-value reference field that references Card paragraphs like we created in the previous article. Once we’ve created this, added it to a content type, and populated some content, we can look at our template options on the frontend:

Let’s use paragraphu002du002dcard-grid.html.twig and replace the default content with the following:

{% embed "@organisms/grid/grid.twig" with {rn  grid_blockname: 'card'rn} %}
  {% block grid_content %}
    {{ content }}
  {% endblock %}
{% endembed %}

Notice first the use of embed. As mentioned before, embed comes with a little more power than extends, notably the ability to pass variables to the original file just like inside an include (second line above). In this case, we are passing the value ‘card’ to grid_blockname, which will make our outer element class be what we expect: card__grid. You’ll also notice that we are replacing the Twig block content we used in Storybook (our for loop) with simply {{ content }}. This is the simple beauty of mapping components to the correct Drupal template layer; for this wrapper element, we merely need to pass in the entire content of the paragraph because we have already defined templates for the grid contents (the cards themselves). We can mock up data however we like in Storybook, but the file in Drupal stays simple and clean and serves only the purpose that matches its level in the component hierarchy. Speaking of that, if you have been following along and refreshing the display in Drupal — you’ll notice we’re missing one piece in Drupal — the grid-item styling that will make the cards be 3 across on large screens.

Grid item

Sticking with the idea of mapping at the correct level in Drupal, let’s open up our nodeu002du002dcard.html.twig file and add the following line in bold to the code we wrote in our last article:

{%rn  set card_modifiers = [rn    'grid-item',rn    card_variation == 'stripe' ? 'stripe' : '',rn  ]rn%}

And then in our _card.scss file, we can add:

.cardu002du002dgrid-item {rn  @include grid-item(3);
}

Now our Card Grid component is styled in both Storybook and Drupal!

Final thoughts

What we covered in this tutorial may be simple in its execution — specifically Twig blocks and the use of extends and embed — but it is an incredibly powerful tool that will be used at every level above the most basic components. In fact, it is what is used in the templates and pages components to power an entire layout. I would encourage you to explore those files, specifically components/04-templates/_default.twig, which provide the default outer markup to all pages as well as the Twig blocks for the Drupal regions. Once you wrap your head around these new concepts, you will be prepared to build a component or template at any level.