Drupal 8 full width layout

Creating a Full-width optional layout using Drupal 8 TWBS3 base theme with the Paragraphs module.

A common layout discussion that frequently arises on a new build, is if a project build requires the ability and flexibility to display content full width of the screen. If using the Bootstrap 3 framework as a starter kit, you have two options that lie ahead. One is the ‘container’ route, meaning your templates will display at responsive fixed widths defined by TWBS3. The opposite option is setting the theme to ‘container-fluid’, this allowing the container to span the entire width of your viewport. Straight out the box, you uncover in the TWBS3 theme page.html.twig template that the main content area width is defined by your decision in the Drupal CMS settings; ‘container’ or ‘container-fluid’. That’s it, you might be reasoning to yourself, but that satisfies my design until;

  • the design requires a full-width background colour but the content is contained in a fixed width
  • the bespoke design requires a full-width banner image and position above or below contained width text regions demands of a bespoke custom layout

This is where the two TWBS options has hold over the design.

A solution

Firstly I cloned the page.html.twig template and removed the TWBS container class {{ container }} from main-container. I then created a new child <div> with the Twig attribute.addClass to set the .container or .container-fluid. The .container class can then be added depending on if a single sidebar or both are used on a page. If no sidebar is in play, the .container-fluid class is added enabling full-width use of the main area. See my page.html.twig alterations highlighted below.

{# Main #}
{% block main %}
<div role="main" class="main-container js-quickedit-main-content">

  {# Header #}
  {% if page.header %}
    {% block header %}
    <div class="{{ container }}">
      <div class="row">
            <div class="col-sm-12" role="heading">
              {{ page.header }}
    {% endblock %}
  {% endif %}

  {# Container Width #}
  {# .container class is appiled if sidebars are used. #}
  {# If there are no sidebars .container-fluid class is applied. #}
  set container_classes = [
  page.sidebar_first and page.sidebar_second ? 'container',
  page.sidebar_first and page.sidebar_second is empty ? 'container',
  page.sidebar_second and page.sidebar_first is empty ? 'container',
  page.sidebar_first is empty and page.sidebar_second is empty ? 'container-fluid'
  <div{{ attributes.addClass(container_classes) }}>
    <div class="row">

This new <div{{ attributes.addClass(container_classes) }}> element I’ve added will host the container or container-fluid class depending on the following;

  • if layout displays left and right sidebars set class of .container
  • if layout only displays left sidebar set class of .container
  • if layout only displays right sidebar set class of .container
  • but if layout displays no sidebars set the class of .container-fluid

So lets recap, layouts with sidebars would require a fixed width container holding the two or three columns together. But if no sidebar content is present the layout can flex out to 100% width. Next up, from the Paragraphs module I cloned the following files;

  • paragraph—default.html.twig
  • paragraph—image.html.twig
  • paragraph—columns-two-uneven.html.twig
  • paragraph—columns-three-uneven.html.twig

These Paragraph types are more commonly used for controlling layout of content and during build became more apparent. In each of these Paragraph files I added the following Twig markup to apply the setting of ‘container’ or ‘ full-width‘(container-fluid) to the Paragraph type.

{# Renders Width Container field. #}
{% if content.field_width_container|render %}
    {% set layout_width_container = content.field_width_container['#items'].getString() %}
    {% set layout_width_container_classes = [
    'container' == layout_width_container ? 'container',
    'full-width' == layout_width_container ? 'full-width',
{% endif %}

{# Merges Width Container field with classes. #}
{% set width_container_field = content.field_width_container|render %}
{% if width_container_field %}
    {% set classes = classes|merge(layout_width_container_classes) %}
{% endif %}

{# Prints div with classes, and content without Width and Background. #}
<div{{ attributes.addClass(classes) }}>
    {{ content|without('field_width_container') }}

Next up, I created the custom field type of ‘Width Container’ made up of a select input with three options:

  1. None
  2. Container
  3. Full-width (aka container-fluid)

This custom field is adopted on each of the Paragraph types i.e ‘Simple and ‘Blank’ and would display on each Paragraph content type.

The caveat

By default your content type layout would always be 100% wide unless you select the ‘Container’ option. But remember if there is a sidebar, you don’t need to set an option and leave ‘none’ selected.


Page view layouts with no left or right side-bars designed enforcing a contained width for content, you need to add a .container class in the view custom class settings as highlighted below.

Let's chat. Tell us a bit about your project.

If you prefer to speak with someone, call 01202 203160 or if you'd like to book a 30 min meeting to see if we can help just let us know and we'll arrange a call with one of our Directors.