How to Create Powerful Container Paragraphs in Drupal 8

Want to learn more about Paragraphs? Then check out our online video course called “Build Edge-to-edge Sites using Paragraphs in Drupal 8“.

In the last Paragraphs tutorial, you were introduced to the module and we created a basic paragraph type called Content. We only skimmed the surface of what the module can really do. To utilize Paragraphs to its full potential you need to learn how to create a container paragraph type and nest paragraph items.

The concept of a container is fairly simple. It’s a paragraph type that has its own paragraph field on it and allows a user to nest paragraph items.

Below is an example of how it’ll be rendered.

Fig 1.0

In this tutorial, we’ll create a container paragraph called Banner, it’ll have two fields: image and paragraphs.

When a banner paragraph is created and an image is uploaded, the image will be displayed as a background style. Now, I do understand there’re multiple ways of doing this, but for simplicity we’ll set it using a background style on the paragraph element.

All nested paragraphs will be rendered inside the container and displayed with the background. If you want to add any other settings, i.e., parallax configuration, you would place it on the container paragraph.

Here is what the end product looks like on a Drupal site.

Fig 1.10

Getting Started

To save time, let’s reuse the paragraph type we created in the last tutorial. Don’t worry, you won’t have to reread the last tutorial again. Simply download this sandbox repo and enable it. Once the module has been enabled you should see the Content paragraph type.

Now make sure you have Paragraphs and Entity Reference Revisions installed.

Below are the Drush and Drupal Console commands to download and install:


$ drush dl paragraphs entity_reference_revisions
$ drush en paragraphs

Drupal Console:

$ drupal module:download paragraphs 8.x-1.0-rc4
$ drupal module:download entity_reference_revisions 8.x-1.0-rc4
$ drupal module:install paragraphs

Create Container Paragraph Type

The first bit of work that needs to be done is create the container paragraph type.

1. Go to Structure, “Paragraphs types” and click on “Add a Paragraphs type”.

Fig 1.1

2. Enter in Banner into Label and click on Save.

Fig 1.2

Add Fields to Container Paragraph Type

We created the Banner paragraph type, let’s now add two fields: Image and Paragraphs (the nested field).

1. Expand the Edit button and click on “Manage fields” on the Banner row.

Fig 1.3

2. Click on “Add field”, Select Image from “Add a new field” and add Image into Label. Then click on “Save and continue”.

Fig 1.4

3. Leave the “Field settings” page as the default and click on “Save field settings”.

4. On the Edit page, check the “Required field” checkbox, scroll to the bottom and click on “Save settings”.

So far we’ve done nothing ground breaking. All we did was create an image field and made it mandatory. Now let’s create a paragraph field which’ll be used to nest the paragraphs.

5. Click on “Add field” again, select Paragraph from “Add a new field” and enter Paragraphs into Label. Then click on “Save and continue”.

Fig 1.5

6. On the next page, leave it as the default then click on “Save field settings”.

7. On the edit page, scroll down to the list of paragraph types and select only Content. This will make sure the right paragraph is available. Then click on “Save settings”.

Fig 1.6

Field Widgets

So far we’ve simply created the fields, let’s now make sure the field widgets are configured.

1. Click on the “Manage form display” tab. If required, you can go ahead and change the widget settings. We’ll leave them as the default. Scroll to the bottom and click on Save.

Fig 1.7

Field Formatters

Finally, let’s quickly configure the field formatters.

1. Click on the “Manage display” tab.

2. Set the Label drop-down on the Paragraphs formatter to - Hidden -.

3. Make sure you move the Image field to the Disabled section. We’ll write a bit of code to add the image as a background to the paragraph. So this formatter isn’t needed.

4. The default settings on the paragraph formatter is fine so we won’t touch it. Scroll to the bottom and click on Save.

Fig 1.8

Implement Preprocess Hook

The final piece to this epic puzzle is the preprocess hook. As mentioned in the introduction the image will be added as a background style. We’ll need to implement this via a preprocess hook.

Copy the code below into a module or theme and replace the string “HOOK” with the actual theme or module name.

function HOOK_preprocess_paragraph__banner(&$variables) {
  $paragraph = $variables['paragraph'];
  if (!$paragraph->field_image->isEmpty()) {
    $image = $paragraph->field_image->entity->url();
    $variables['attributes']['style'][] = 'background-image: url("' . $image . '");';
    $variables['attributes']['style'][] = 'background-size: cover;';
    $variables['attributes']['style'][] = 'background-position: center center;';

Don’t forget to clear the site cache after adding the hook.

If the above code doesn’t work make sure that the machine name of the banner paragraph is simply banner and that the image field name is field_image. If the machine name for the paragraph or field is different then the code won’t work.

Create a Banner Paragraph

I’ll assume you already added the paragraph field on a content type. We learnt how to do that in the last tutorial. If this is new to you then please read the “Add Paragraph field” in the previous tutorial.

Go ahead and create an article with a paragraph field and create a banner. If everything has been setup, you should see the text in the Content paragraph displayed with the image as the background.

Fig 1.9


Creating a container paragraph is more advanced but the concept is simple. It simply groups a bunch of paragraphs together and that’s it. When creating these types of paragraphs, it’s good to stand back and map out all the possible paragraph types. Building these types of paragraphs can get very messy if the site requirements keep changing.

28 thoughts on “How to Create Powerful Container Paragraphs in Drupal 8”

  1. In your video you could have using PhpStorm’s Drupal integration to help you figure out the name of the function to do the preprocess hook by just typing function then start typing preprocess. It would have discovered the name of the function you needed and replace hook for your module name for you.

  2. The default image field only accepts files from the editor’s disk, and uses absolute URLs on the displayed page. This breaks the display if you develop on an internal server. Is there a way around this?

    1. Frederick J. Henderson

      Jim Rome, try the Media Browser as the widget for the Form Display. This will allow selecting previously uploaded images and also allow uploading new ones.

  3. Justin Gauthier

    Any possible reason you can think of why nested paragraph image fields would not be uploading content or throwing strange validation errors

    I have a pretty awesome parent paragraph type that houses a bunch of sub paragraph types.

    I have one paragraph type named “Column Content” It contains two fields, Leading Image and Column Text. “Column Content” gets used a few other paragraph types for example, “Company Callout”. “Company Callout” has some unique fields on it and also includes “Column Content” as an entity reference revision. Then “Company Callout” gets used in a “Page Blocks” Paragraph type. So with this structure its Page Blocks > Company Callout > Column Content and a image field on Column content is throwing the errors. When I arrange the structure like this Page Blocks > Column Content all fields validate and function as expected.

    Any insight on this paragraph inception is helpful.

    1. Hi Justin,

      Are you getting any PHP errors or JavaScript errors? Have you heavily customized the paragraph types, with preprocesses? There could be a lot of reasons why you’re having issues. It could be the theme, overridden templates or a custom module.


      1. Justin Gauthier

        No PHP errors. No JS errors. Its not user permissions I chmod -R 777 to test that out. The strange thing is that this exact database and code base works fine locally and also on a different host than what production is running on.

        The only thing I can think of is that maybe there is some php module not active on the production server. Or maybe its hitting some sort of memory limit and not throwing an error.

        The big sweeping things I can think of I have tested. I’m just going to dig in really start comparing what the difference is between environments.

        1. Try uploading a file using another field which isn’t on a paragraph type. Does the site have trouble uploading any type of file? Also look for differences in PHP versions.

  4. Hello, good work and good blog by the way!
    Just a suggestion by rendering the image by using the url display format in display option of the image field. But maybe we need extra-work by overriding the paragraph template or the container in general to add the background attribute.

  5. I created the prepossess but I still cannot determine where to place is. I am using Adaptivethemes for D8 having created a subtheme using AT theme generator. The .theme file is labeled as a Windows Theme File. The .theme file cannot be opened with notepad or sublime.

  6. Sorry, where is located the file with the “HOOK_preprocess_paragraph__banner(&$variables)” function?
    thank you

  7. Hi Ivan,
    I use Media field instead of Image field but the output path for the image background is wrong. It pointed to the media content url instead of the image path. How can i fix this?


  8. Shashank Yadav

    Is this possible to use scheduler for paragraph type?
    I want to set published and unpublished date in paragraph type. Please let me know if you have any idea.

  9. Thank you for your tutorial. It seems that there are a whole lot of nested div tags already. Do you still mind this on projects or leave them as is? If you mind them, can the templating engine handle very specific template files for the container and nested paragraphs?

  10. I know this post is dated but I would really like to get this to work. I have created to the paragraph types with the exact same machine names as instructed but no luck at all getting the preprocessor to fire off. I have created the following in my w3css_paul_subtheme .theme file:


    * @file
    * Add your custom theme override functions here.
    function w3css_paul_subtheme_preprocess_paragraph__banner(&$variables) {
    echo "Hello world!”;
    $paragraph = $variables[‘paragraph’];
    if (!$paragraph->field_image->isEmpty()) {
    $image = $paragraph->field_image->entity->url();
    $variables[‘attributes’][‘style’][] = ‘background-image: url(“‘ . $image . ‘”);’;
    $variables[‘attributes’][‘style’][] = ‘background-size: cover;’;
    $variables[‘attributes’][‘style’][] = ‘background-position: center center;’;

    I don’t even get the echo to work.
    Any guidance on where to go to troubleshoot a preprocessor?

    1. Hi Paul,

      This is a tricky one.

      Here’s is how I would debug this:

      – Make sure the function name is correct HOOK_preprocess_paragraph__banner
      – Make sure the paragraph type machine name is banner
      – Rebuild the site cache, go to Configuration -> Performance
      – Try overriding another preprocess, i.e., hook_preprocess_page for example
      – Make sure the theme (w3css_paul_subtheme) is actually enabled (this has happened to me :))

      Hope this helps.


  11. Servus, Ivan!
    Great tutorial which helped me a lot to get to fits with Bootstrap. However, your code isn’t valid any more, you have to use

    $image = $paragraph->field_image->entity->createFileUrl();
    instead of
    $image = $paragraph->field_image->entity->url();

    Hope this prevents other people from scratching heads 🙂

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top