A First Run with Component Theming

Missteps, Learnings, and Success

Slides: https://wheatpenny.github.io/D8-component-theming/

Download theme: componenttheme.zip

“The world needs more people who are two days into learning something writing about the problems of people who are one day in.”
-- Patrick McKenzie
(https://twitter.com/patio11/status/803825771349426176)

Levi Sigworth

xiah.io drupal.org/u/wheatpenny @levisigworth
Why listen to what I have to say?

Goals of this project

Approve the design in the browser, not with a Photoshop rendering
Show infinite breakpoints. Resize text based on viewport. Automatically import real text. Inline documentation on how to use components.
A front end style guide perfectly in sync with production
  • themename
    • source (patternlab files)
    • templates (drupal theme files)
    • dest (generated output: CSS, JS, icons, etc)
    • themename.yml.info

(Highlighted folders and files of our Drupal 8 component-based theme)

Publish the front end style guide publicly

How?

We're going to reach these goals with component theming in Drupal 8.

Why component theming?

These goals are great, but why even bother? This is a lot of effort and something brand new to learn.

Make changes to exactly the part of the site you want.

Those changes roll out in a predictable manner.

Two CSS properties walk into a bar. A barstool in an entirely different bar falls over.

What is component theming?

Bundles of HTML, CSS, and JS that can be moved around the site and remain CONSISTENT and PREDICTABLE

Example: Code Widget

Final Generated HTML

							
    
			(CONTENT HERE)
    
  

(CAPTION HERE)

Pattern Lab owns a template that Drupal imports. Drupal inserts content and displays the markup.

Final Generated CSS

							
.paragraphs-code {
  clear: both;
  padding: 0 0 20px 20px;
  border-left: #f7951d 2px solid;
  margin-left: 0;
}

@media (min-width: 1250px) {
  .paragraphs-code {
    padding-left: 40px;
    margin-left: -40px;
  }
}

.paragraphs-code__code {
  background-color: #f2f2f2;
  overflow: scroll;
}

.paragraphs-code__caption {
  color: #7a7a7a;
  border-bottom: 1px solid #f2f2f2;
  padding-bottom: 5px;
}

.paragraphs-code__text {
	margin-bottom: 0;
}
						
					

Pattern Lab generates this CSS, and the Drupal theme imports this CSS file.

No JS for this widget

Quick Break 1: Buzzwords and Terminology

Front End Style Guide

The deliverable we are using to define client acceptance in the browser.

Pattern Lab and Atomic Design

The design system I chose to implement a front end style guide.

First Component

Display code examples in my writing posts.

Step 1

Understand that there is a need for a component.

system thinking

Step 2

Create the component in Pattern Lab.

  • Twig file: HTML
  • SCSS file: compiles to CSS
  • JSON file: sample content
  • Markdown file: usage documentation
  • JS file: Javascript

Easy with Pattern Lab Starter

							
npm run new
							
						

https://github.com/phase2/pattern-lab-starter

								
<{{ element ?: "figure" }} class="paragraphs-code">
  
    
      {{ code }}
    
  
{% if caption %}

{{ caption }}

{% endif %}
Twig markup
							
.paragraphs-code {
  clear: both;
  padding: 0 0 $spacing--l $spacing--l;
  border-left: $c-code-border 2px solid;
  margin-left: 0;

  @include breakpoint($bp--xxlarge) {
    padding-left: $spacing--l*2;
    margin-left: -$spacing--l*2;
  }

  &__code {
    background-color: $c-code-bg;
    overflow: scroll;
  }

  &__caption {
    color: $c-byline-color;
    border-bottom: 1px solid $c-byline-border;
    padding-bottom: $spacing--sm;
  }
  &__text {
    margin-bottom: 0;
  }
}
							
						
SCSS file
							
{
  "code": "drup(){cd /var/www/$1/sites/default/ (cdd && git pull && drush updatedb)}",
  "caption": "This example shows how to automate your startup environment."
}
							
						
JSON file

Step 3

Test your pattern in the browser!

Step 4

Build functionality in Drupal

Paragraphs

Step 5

Figure out template name in Drupal

https://www.drupal.org/docs/8/theming/twig/debugging-twig-templates

Step 6

Pull component Twig template into Drupal theme.

							
{% embed "@molecules/paragraphs-code.twig"
  with {
  "code": content.field_figure_code|field_value,
  "caption": content.field_figure_caption|field_value
  }
 %}
{% endembed %}
							
						
paragraph--paragraphs-code.html.twig

Quick Break 2: Buzzwords and Terminology

Paragraphs

Drupal modules that allows editors to create small, movable chunks of content. Replaces a big Body field.

SCSS (or SASS)

Generates the final CSS file

Makes BEM naming structure easier to implement.

BEM

Block, Element, Modifier. CSS naming convention

Twig

HTML templating engine in D8. Replaces PHPTemplate in D7.

npm

Comes from node.js. It's a package manager. YOU DON'T NEED TO BE AN EXPERT HERE...just have to get it installed.

Second Component

Show Images in Writing Posts

Step 1

Understand that there is a need for a component. (system thinking)

Step 2

Create the component in Pattern Lab.

								
<{{ element ?: "figure" }} class="paragraphs-image{% if styleModifier %} paragraphs-image--{{ styleModifier }}{% endif %}">

  
{% block img %} {% include "@atoms/_img.twig" %} {% endblock %} {% if byline %} {% endif %}
{% if caption %}

{{ caption }}

{% endif %}
Twig markup
							
.paragraphs-image {
  clear: both;
  margin-left: 0;
  margin-right: 0;
  margin-bottom: $spacing--l*2;
  display: table;

  // styleModifier: left
  &--left {
    float: none;
    margin-left: auto;
    margin-right: auto;
    @include breakpoint($bp--large) {
      float: left;
      margin: 0 $spacing--l $spacing--l 0;
      max-width: 600px;
    }
    @include breakpoint($bp--xlarge) {
      //margin: 0 $spacing--l $spacing--l -05%;
      max-width: 700px;
    }
    @include breakpoint($bp--xxxlarge) {
      margin: 0 $spacing--l $spacing--l -15% ;
    }
  }

  // styleModifier: right
  &--right {
    float: none;
    margin-left: auto;
    margin-right: auto;
    @include breakpoint($bp--large) {
      float: right;
      margin: 0 0 $spacing--l $spacing--l;
      max-width: 600px;
    }
    @include breakpoint($bp--xlarge) {
      //margin: 0 -05% $spacing--l $spacing--l;
      max-width: 700px;
    }
    @include breakpoint($bp--xxxlarge) {
      margin: 0 -15% $spacing--l $spacing--l;
    }
  }

  // styleModifier: hero
  &--hero {
    margin-left: auto;
    margin-right: auto;
  }

  &__image {
    position: relative;
    float: left;
    img {
      display: block;
      width: 100%;
    }
  }
  &__byline {
    position: absolute;
    bottom: 0;
    right: 0;
    @include knockout;

    // styleModifier: hero
    .paragraphs-image--hero & {
      @include breakpoint($bp--xxlarge) {
        transform: rotate(90deg);
        transform-origin: 100% 100%;
      }
    }

    // styleModifier: left
    .paragraphs-image--left & {
      @include breakpoint($bp--xxlarge) {
        left: inherit;
        right: auto;
        transform: rotate(270deg);
        transform-origin: 0 100%;
      }
    }

    // styleModifier: right
    .paragraphs-image--right & {
      @include breakpoint($bp--xxlarge) {
        transform: rotate(90deg);
        transform-origin: 100% 100%;
      }
    }


  }
  &__caption {
    color: $c-byline-color;
    border-bottom: 1px solid $c-byline-border;
    padding-bottom: $spacing--sm;
    clear: both;
    display: table-caption;
    caption-side: bottom;
  }

  &__text {
    margin-bottom: 0;
  }
}
							
						
SCSS file
							
{
  "img": "http://placehold.it/1000x400",
  "byline": "Freddy Foto",
  "bylineurl": "https://www.example.com",
  "caption": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud "
}
							
						
JSON file

Step 3

Test your pattern in the browser!

Step 4

Build functionality in Drupal

Paragraphs

Theme Function

							
/**
* Implements hook_preprocess_HOOK() for paragraph--paragraphs-image.html.twig.
*/
function patternlab_preprocess_paragraph__paragraphs_image(&$variables) {
 $paragraph = $variables['paragraph'];
 // Get the value of the image style and add it as a class on the image field.
 $display_image = $paragraph->get('field_figure_position')->value;
 $variables['display_image'] = $display_image;
 }
							
						
Theme function: place in themename.theme

Step 5

Figure out template name in Drupal

Step 6

Pull component Twig template into Drupal theme.
							
{% embed "@molecules/01-paragraphs-image.twig"
  with {
  "byline": content.field_figure_byline.0["#title"],
  "bylineurl": content.field_figure_byline.0["#url"],
  "caption": content.field_figure_caption|field_value,
  "styleModifier": display_image
  }
 %}
 {% block img %}
  {{ content.field_figure_image|field_value }}
 {% endblock %}
{% endembed %}
							
						
paragraph--paragraphs-image.html.twig

Third Component

Show Cards in Views

Step 1

Understand that there is a need for a component. (system thinking)

Step 2

Create the component in Pattern Lab.

								
<{{ element ?: "div" }} class="writing-card{% if styleModifier %} writing-card--{{ styleModifier }}{% endif %}">
  
    
{% block img %} {% include "@atoms/_img.twig" %} {% endblock %}
{% if title %}

{{ title }}

{% endif %} {% if body %}

{{ body }}

{% endif %}
Twig markup
							
.writing-card {
  position: relative;

  //styleModifier: hero
  &--hero {
    margin-bottom: $spacing--l*2;
  }

  &__caption {
    border-top: $spacing--l/4 solid $c-writing-card-caption-border;
    border-bottom: $spacing--l/4 solid $c-writing-card-caption-border;

    // styleModifier: hero
    .writing-card--hero & {
      border-top: $spacing--l/4 solid $c-writing-card--hero-caption-border;
      border-bottom: $spacing--l/4 solid $c-writing-card--hero-caption-border;
      position: relative;

      @include breakpoint($bp--medium) {
        position: absolute;
        bottom: 0;
        width: 100%;
      }
    }
  }

  &__title {
    @include knockout;
    background-color: $c-writing-card-caption-bg;
    font-weight: normal;
    margin-top: 0;
    margin-bottom: 0;
  }

  &__body {
    @include knockout;
    background-color: $c-writing-card-caption-bg;
    font-style: italic;
  }
  &__text {
    margin-bottom: 0;
  }
}
							
						
SCSS file
							
{
  "img": "http://placehold.it/650x250",
  "url": "http://www.example.com",
  "title": "The Cobbler's Children: Pattern Lab and being your own client"
}
							
						
JSON file

Step 3

Test your pattern in the browser!

Step 4

Build functionality in Drupal

Views

View Modes!

Structure > Display Modes > View Modes

Add View Modes for content.

Enable View Modes on Content Type

Configure for each content type:

Structure > [Content Type] > Manage Display

Enable under "Custom Display Settings."

Step 5

Figure out template name in Drupal

Step 6

Pull component Twig template into Drupal theme.

Each View Mode gets a Drupal template, but they all use the same component.

							
{% embed "@molecules/01-writing-card.twig"
  with {
    "url": url,
    "title": label,
    "body": content.field_card_blurb|field_value
  }
 %}
  {% block img %}
   {{ content.field_card_image|field_value }}
  {% endblock %}
{% endembed %}
							
						
node--writing--card.html.twig
							
{% embed "@molecules/01-writing-card.twig"
  with {
    "url": url,
    "title": label,
    "body": content.field_card_blurb|field_value,
    "styleModifier": "hero"
  }
 %}
  {% block img %}
   {{ content.field_card_image|field_value }}
  {% endblock %}
{% endembed %}
							
						
node--writing--card-hero.html.twig
							
{% embed "@molecules/01-writing-card.twig"
  with {
    "url": url,
    "title": label,
    "body": content.field_card_blurb|field_value
  }
 %}
  {% block img %}
   {{ content.field_card_image|field_value }}
  {% endblock %}
{% endembed %}
							
						
node--writing--card-text-only.html.twig

What did I learn?

What were my wrong assumptions?

Wrong Assumption #1

Drupal would be my test area for real content.

Next Time

Real content in Pattern Lab. Take the time to do this!

Exceptionally important if your front end style guide is not perfectly in sync with the live site. You need to see if your ideas actually work!

Wrong Assumption #2

I wanted to provide every template Drupal would use.

Instead

I used blocks in Twig heavily to create replaceable sections.

Wrong Assumption #3

I thought that I would be theming a lot of views with fields.

Instead

I themed view modes that were then used in views.

(Review) Goals of this project

Approve the design in the browser, not with a Photoshop rendering

Yes

A front end style guide perfectly in sync with production

Yes

Publish the front end style guide publicly

No, not yet

Resources

Required Drupal Modules

Drupal 8 Component Theming Initiative

Learn and contribute at the same time!

DrupalTwig Slack channel

I've learned a ton here. People are very helpful as long as you put in the effort.

Front End Style Guides

Atomic Design and Pattern Lab

Pattern Lab Starter

BEM

SASS

Use SCSS formatting!

Additional Reading (1)

Additional Reading (2)

There is an extensive list of additional resources at the bottom of this page.

Thank you!

Feedback: https://github.com/wheatpenny/D8-component-theming. File an issue!