Cute Bootstrap 4 news article cards for Drupal 8 Views

I’ve been working with Drupal 8 more and more lately and have been poking around with the power and flexibility built into Views.

Views: A Drupal 8 module that lets you construct custom displays to show which content in the way you want. https://www.drupal.org/docs/8/core/modules/views

I’ve also gleefully adopted Bootstrap 4 for a new project. It’s hella cute.

Bootstrap: A CSS and javascript framework that lets you quickly build a responsive UI components, like cards. https://v4-alpha.getbootstrap.com/ Bootstrap 4 is the latest release, still in alpha as of whenever I posted this.

In my past experiences, building a custom display in whatever CMS tended to require me to get into template files and write my own HTML/CSS/PHP from scratch which is fine, whatever. But Views and Bootstrap 4 let me use the Drupal 8 admin interface to build out my own with minimal coding.

Quick, cute Bootstrap 4 cards for Drupal 8 views

What I’ll be making

I want to display Drupal 8 news articles as Bootstrap 4 cards. Article is a default Drupal 8 content type. Bootstrap 4 provides a card component: https://v4-alpha.getbootstrap.com/components/card/

Bootstrap 4’s Card component example.

What I’m Using

  • A Drupal 8 website with some Articles.
  • A Drupal 8 theme that includes Bootstrap 4 in there. In my case, I’m building a custom theme based on Bootstrap 4.
  • My favorite placeholder image service is http://unsplash.it/
  • My favorite placeholder text service is http://www.rikeripsum.com

One could apply these principles to any other CSS framework, I’m sure. Like, I also really like http://bulma.io/ and they also have a card component.

How it works

Basically, I created a View with the content I wanted, then used a Replacement Pattern to re-write how that content showed up, wrapping it up in the Bootstrap 4 card component markup.

1. Create a new View

I already had a View set up for the Article content type with a basic Page and Block Display, so I created a new Page Display.

How to create a new View: https://www.drupal.org/docs/8/core/modules/views/create-a-simple-page-view

Here’s how it looks in my View

How my new Cards display looks in Views

And going through those settings step-by-step:

Display name: Cards
(Use whatever name makes sense to you. Does not show up on the front.)

Title: News
(Name that will show up on the page.)

Format
Format: HTML List | Settings (We will come back to these settings)
Show: Fields | Settings (We will come back to these settings)

Fields (Add in these fields in this order and check “Exclude from display”. Do not ‘Create a label’.)
Content: Image (Formatter: URL to Image)
Content: Title
Content: Authored on (I use the custom date format D, M n, Y - ga)
Content: Body (Formatter: Summary or trimmed)
Content: Path
Global: Custom text (This is the magic. We will come back to this)

Filter Criteria
Content: Publishing status (= Yes)
Content: Content type (= Article)

Page Settings
Path: /cards (Create a url for this page)

Header
(I made a Global: Text area header so there would be some text before all my news.)

2. Make columns and rows

I want the articles to appear in columns.

Back under Format: HTML List | Settings I added Bootstrap 4 classes to the Row class field. This will add classes to each li element in the HTML list. Just spaces between, order doesn’t matter.

col-md-6 col-lg-4 mb-3

According to Bootstrap 4’s grid documentation, col-md-6 means that on medium width screens, the column with take up 6/12 columns, so half. Then, when the screen is wide, they will take up 4/12 columns, so col-lg-4. mb-3 is a utility class that adds a margin-bottom. See Bootstrap 4’s utility class documentation.

That done, I need to add classes to the ul itself under List class.

list-unstyled row

list-unstyled is Bootstrap 4’s way of removing all list-y formatting from lists. row makes columns work.

3. Make cards

Each of the six ‘Content:’ fields I pulled in and hid serve the purpose of getting those pieces of content available for me to fuss with, i.e. weave in with my own Bootstrap 4 HTML.

Look again at Bootstrap 4’s card component markup:

<div class="card" style="width: 20rem;">
<img class="card-img-top" src="..." alt="Card image cap">
<div class="card-body">
<h4 class="card-title">Card title</h4>
<p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
<a href="#" class="btn btn-primary">Go somewhere</a>
</div>
</div>

Edit Sept 1, 2017: Bootstrap 4 is now in beta, so there have been some changes.card-block is now .card-body so the example code in this article have been updated.

They have an example of a card with an image at the top, and the title, summary, and a button inside. Looking at that documentation more, I decided I wanted this set-up:

<div class="card h-100">
<a href="#"><img src="#" class="card-img-top" width="100%"></a>
<div class="card-body">
<h3 class="card-title"><a href="#">Article Title</a></h3>
<p>Authored On</p>
<p>Summary</p>
</div>
<div class="card-footer">
<a href="#" class="btn btn-sm btn-secondary">Read More</a>
</div>
</div>

h-100: Bootstrap 4 class to set an element’s height to 100%, which helps the card fill the height of the column, so all the cards will look the same height.

width="100%": Not 100% sure why, but my images were warping without this on there. *shrug* Flexbox fun la la la

card-footer: The card component came with a footer which I thought looked cool.

btn btn-sm btn-secondary: Bootstrap 4 button classes. There are so many to choose from.

Now, open the Global: Custom text field (which should be the last in the list of fields). Expand the Replacement Patterns panel and then and you can see how all the pieces from those ‘Content:’ fields are now available to us using Twig syntax.

What is Twig?
Twig is an easy way to work with PHP and is built into Drupal 8. You don’t need to know Twig to pull this off, but you can learn more here: https://www.drupal.org/docs/8/theming/twig When you see all those curly boys {{}} know that’s probably Twig.
  • {{ field_image }} == Image
  • {{ title }} == Title
  • {{ created }} == Authored on
  • {{ body }} == Body
  • {{ path }} == Path
  • {{ nothing }} == Custom text

I basically just dropped these replacement tokens into my HTML.

<div class="card h-100">
{% if field_image %}
<a href="{{ path }}">
<img src="{{ field_image }}" class="card-img-top" width="100%">
</a>
{% endif %}
  <div class="card-body">
<h4 class="card-title">{{ title }}</h4>
<p>{{ created }}</p>
<div>{{ body }}</div>
</div>
<div class="card-footer">
<a href="{{ path }}" class="btn btn-sm btn-secondary">Read More</a>
</div>
</div>

{% if field_image %} ... {% endif %}: This is a little Twig conditional statement. If this article has an image, then show it; if not, don’t. This is the power of mighty Twig. Without this conditional, articles without images had a funny gap at the top.

{{ title }}: Actually provides title as an a element, so neat.

{{ path }}: This is a cool trick. The Content: Path field just grabs the url of the Article, so we can make our own links/buttons.

Hint: Equal height cards

Drupal 8 is “helpful” in that it wraps everything in a million divs, but in this case, it gets in my way a bit.

The cards aren’t equal height.

Even though I told the cards to be height: 100% with h-100, they still aren’t stretching to match. It’s because the card isn’t the direct child of the equal height columns. If I go to Show: Fields | Settings and uncheck ‘Provide default field wrapper elements’, it removes all that extra nesting.

Hint: Calendar icon by the date

This is another Views/Twig lifehack. You’ll need Font Awesome set up in your theme, but even if you don’t, you can still fiddle with field display for fun.

Open the settings for Content: Authored on and open the Rewrite Results panel. Check ‘Override the output of this field with custom text’.

Again, Views provides us with some Twig replacement tokens. Here’s what I used:

<span class="fa fa-calendar" aria-hidden="true"></span> {{ created }} {{ created_value }}

Edit Aug 30, 2017: To make icons more accessible, I used <span> instead of <i> and added the ARIA <aria-hidden="true"> so it will be available to visual users, but ignored by most screenreaders.

What is Font Awesome?
A massive icon font set that makes it easy to drop icon elements into HTML and CSS. http://fontawesome.io/

What do you think?

This was just my solution for leveraging the power of a fav framework into Drupal 8 without too much extra fuss. You could do your own thing.

You could change this up however you wanted, applying this workflow to other content types, building with other components or frameworks, etc.