Step 1: Create custom theme
Step 2: Install Paragraphs contrib module
Step 3: Create a paragraph
Step 4: Embed react app in theme
Step 5: Configure library
Step 6: Preprocess paragraph
Step 7: Attach library to paragraph template
Step 1: Create custom theme
Step 2: Install Paragraphs contrib module
Step 3: Create a paragraph
Step 4: Embed react app in theme
Step 5: Configure library
Step 6: Preprocess paragraph
Step 7: Attach library to paragraph template
Within your Drupal 8 project, define a custom theme.
Drupal paragraphs is a contributed module that ...
We use composer to manage our dependencies, ___
Once enabled, a paragraph can be create in the Admin UI under ???
If you are using Drupal command line tool, run drush cex
to export the configuration from the UI into the codebase.
Copy the contents of project/web/modules/contrib/paragraphs/templates/paragraph.html.twig
into project/web/themes/custom/test/templates/paragraphs/paragraph--[name of paragraph here].html.twig
, and theme your paragraph below.
{#
/**
* @file
* Default theme implementation to display a paragraph.
*
* Available variables:
* - paragraph: Full paragraph entity.
* Only method names starting with "get", "has", or "is" and a few common
* methods such as "id", "label", and "bundle" are available. For example:
* - paragraph.getCreatedTime() will return the paragraph creation timestamp.
* - paragraph.id(): The paragraph ID.
* - paragraph.bundle(): The type of the paragraph, for example, "image" or "text".
* - paragraph.getOwnerId(): The user ID of the paragraph author.
* See Drupal\paragraphs\Entity\Paragraph for a full list of public properties
* and methods for the paragraph object.
* - content: All paragraph items. Use {{ content }} to print them all,
* or print a subset such as {{ content.field_example }}. Use
* {{ content|without('field_example') }} to temporarily suppress the printing
* of a given child element.
* - attributes: HTML attributes for the containing element.
* The attributes.class element may contain one or more of the following
* classes:
* - paragraphs: The current template type (also known as a "theming hook").
* - paragraphs--type-[type]: The current paragraphs type. For example, if the paragraph is an
* "Image" it would result in "paragraphs--type--image". Note that the machine
* name will often be in a short form of the human readable label.
* - paragraphs--view-mode--[view_mode]: The View Mode of the paragraph; for example, a
* preview would result in: "paragraphs--view-mode--preview", and
* default: "paragraphs--view-mode--default".
* - view_mode: View mode; for example, "preview" or "full".
* - logged_in: Flag for authenticated user status. Will be true when the
* current user is a logged-in member.
* - is_admin: Flag for admin user status. Will be true when the current user
* is an administrator.
*
* @see template_preprocess_paragraph()
*
* @ingroup themeable
*/
#}
{%
set classes = [
'paragraph',
'paragraph--type--' ~ paragraph.bundle|clean_class,
view_mode ? 'paragraph--view-mode--' ~ view_mode|clean_class,
not paragraph.isPublished() ? 'paragraph--unpublished',
]
%}
{% block paragraph %}
<section {{ bem('cards', [], '', classes) }}>
{% block content %}
<div {{ bem('container', [], 'cards', []) }}>
{{ content.field_section_title }}
{{ content.field_description }}
<div id="react-app" class="paragraph--body bg-whisperGray"></div>
</div>
{% endblock %}
</section>
{% endblock paragraph %}
We actually created the react app before our the repository for this site was set up, but you can tackle this step at any point along the process.
We added our react app within project/web/themes/custom/test/scripts/react-app
The relevant code within App.js:
import React, from 'react';
import ReactDOM from 'react-dom';
const App = ({ uuid }) => {
let data = drupalSettings.testReact[uuid];
...
};
Object.keys(drupalSettings.testReact || {}).forEach((uuid) => {
ReactDOM.render(<App uuid={uuid} />, document.querySelector('#pg-' + uuid));
});
project/web/themes/custom/test/test.libraries.yml
react-app:
js:
build/js/app.js: { minified: true }
dependencies:
- core/drupalSettings
- test/vendors-app
vendors:
js:
build/js/vendors~global.js: { minified: true }
vendors-app:
js:
build/js/vendors~app.js: { minified: true }
project/web/themes/custom/test/test.theme
<?php
/**
* @file
* Theme functions.
*/
include 'preprocess/paragraph.preprocess.inc';
project/web/themes/custom/test/preprocess/paragraph.preprocess.inc
<?php
/**
* @file
* Theme preprocess function for paragraphs.
*/
/**
* Implements hook_preprocess_paragraph().
*/
function custom_preprocess_paragraph(&$variables) {
if (empty($variables['paragraph'])) {
return;
}
/* @var \Drupal\paragraphs\Entity\Paragraph $paragraph */
$paragraph = $variables['paragraph'];
$variables['uuid'] = $paragraph->uuid();
switch ($paragraph->bundle()) {
case 'cards':
// Add data to Drupal settings.
$variables['#attached']['drupalSettings']['test'][$paragraph->uuid()] = $cards;
break;
...
}
}
#
/**
* @file
* Default theme implementation to display a paragraph.
*
* Available variables:
* - paragraph: Full paragraph entity.
* Only method names starting with "get", "has", or "is" and a few common
* methods such as "id", "label", and "bundle" are available. For example:
* - paragraph.getCreatedTime() will return the paragraph creation timestamp.
* - paragraph.id(): The paragraph ID.
* - paragraph.bundle(): The type of the paragraph, for example, "image" or "text".
* - paragraph.getOwnerId(): The user ID of the paragraph author.
* See Drupal\paragraphs\Entity\Paragraph for a full list of public properties
* and methods for the paragraph object.
* - content: All paragraph items. Use {{ content }} to print them all,
* or print a subset such as {{ content.field_example }}. Use
* {{ content|without('field_example') }} to temporarily suppress the printing
* of a given child element.
* - attributes: HTML attributes for the containing element.
* The attributes.class element may contain one or more of the following
* classes:
* - paragraphs: The current template type (also known as a "theming hook").
* - paragraphs--type-[type]: The current paragraphs type. For example, if the paragraph is an
* "Image" it would result in "paragraphs--type--image". Note that the machine
* name will often be in a short form of the human readable label.
* - paragraphs--view-mode--[view_mode]: The View Mode of the paragraph; for example, a
* preview would result in: "paragraphs--view-mode--preview", and
* default: "paragraphs--view-mode--default".
* - view_mode: View mode; for example, "preview" or "full".
* - logged_in: Flag for authenticated user status. Will be true when the
* current user is a logged-in member.
* - is_admin: Flag for admin user status. Will be true when the current user
* is an administrator.
*
* @see template_preprocess_paragraph()
*
* @ingroup themeable
*/
#}
{{ attach_library('test/react-app') }}
{%
set classes = [
'paragraph',
'paragraph--type--' ~ paragraph.bundle|clean_class,
view_mode ? 'paragraph--view-mode--' ~ view_mode|clean_class,
not paragraph.isPublished() ? 'paragraph--unpublished',
]
%}
{% block paragraph %}
<section {{ bem('cards', [], '', classes) }}>
{% block content %}
<div {{ bem('container', [], 'cards', []) }}>
{{ content.field_section_title }}
{{ content.field_description }}
<div id="pg-{{ uuid }}" class="paragraph--body bg-whisperGray"></div>
</div>
{% endblock %}
</section>
{% endblock paragraph %}