Implement Foundation components as paragraphs

Foundation is a front end framework I used on some recent projects. There is a Drupal theme you can build with that adds Foundation features to the base elements and sets up your sass files as a Foundation project. I'd like to build a library of Foundation components available as Drupal paragraphs, so I can quickly get started with them on projects.

I'd like to start with a simple grid of items that users can add as a paragraph. I'm going to implement the Card component in Foundation, and wrap it with Flex Grid.

https://foundation.zurb.com/sites/docs/card.html

https://foundation.zurb.com/sites/docs/flex-grid.html

First, create a Card paragraph and add a title and body field.

Next, create a Cards paragraph that has a cards paragraph field.

 

Here's the tricky part, we have a module file that does 3 things:

First it alters the paragraphs theme suggestions to set up our own theme hook for the card and cards paragraphs.

Then define the theme hook, with render element and base hook. I may revisit and simplify this in the future.

Lastly, a preprocess function for the theme hooks sets up the variables I need in the templates.

 

Use view() to render an entity or field, or use ->value to get a raw value.

 

common_paragraphs.module


/**
 * Implements hook_theme_suggestions_HOOK_alter().
 */
function common_paragraphs_theme_suggestions_paragraph_alter(
  array &$suggestions, array $variables) {
  $paragraph = $variables['elements']['#paragraph'];
  if ($paragraph->getType() === 'cards') {
    $suggestions[] = 'common_paragraphs_cards';
  }
  if ($paragraph->getType() === 'card') {
    $suggestions[] = 'common_paragraphs_card';
  }
}

/**
 * Implements hook_theme().
 */
function common_paragraphs_theme($existing, $type, $theme, $path) {
  return [
    'common_paragraphs_cards' => [
      'render element' => 'elements',
      'base hook' => 'paragraph'
    ],
    'common_paragraphs_card' => [
      'render element' => 'elements',
      'base hook' => 'paragraph'
    ],
  ];
}

/**
 * Render the card.
 */
function template_preprocess_common_paragraphs_card(&$variables) {
  $paragraph = $variables['elements']['#paragraph'];
  $variables['card'] = [
    'title' => $paragraph->get('field_card_title')->value,
    'body' => $paragraph->get('field_card_body')->value,
  ];
}

/**
 * Render the cards.
 */
function template_preprocess_common_paragraphs_cards(&$variables) {
  $paragraph = $variables['elements']['#paragraph'];
  $variables['cards_title'] = $paragraph->get('field_title')->value;
  foreach ($paragraph->get('field_cards') as $paragraph) {
    $variables['card'][] = $paragraph->view();
  }
}

 

Once you get through the hard part above, you're all clear for easy theming.

This is common_paragraphs_cards.html.twig, where we set up the wrapper for the cards.

<div class="grid-container fluid">
  <h2>{{ stats_title }}</h2>
  <div class="grid-x grid-padding-x small-up-2 medium-up-4 large-up-6">
    {{ stats }}
  </div>
</div>

 

In common_paragraphs_card.html.twig, we can set up the individual card.

<div class="cell">
  <div class="card">
    <h3>{{ card.label }}</h3>
    <div class="card-section">
      {{ card.value }}
    </div>
  </div>
</div>

 

At this point, you can create a Cards paragraph with several Card(s) on it, and it should render as Foundation cards in a fluid grid. I'd like to contribute these back as a module once I'm done, and you won't have to do this at all. If you want to provide different output, you can copy the template into your theme and customize there.

If you want to create components for any front end framework, or even scratch components, this technique will work for you. I recommend creating the paragraphs and setting up the templates, then implementing the template html with dummy content in order to figure out the variables you need to code in the preprocessor.