Adding Magento 2 Containers

Magento uses containers and blocks to structure the layout of a page. Containers define the structure of the page and do not contain any additional content, and occasionally you may need to go about adding Magento 2 containers that contain custom functionality from the blocks that reside within these containers.

In order to do this, specify a <container> node within your layout file. Usually, a container definition will reside within the pair of <body> nodes.

In the example below, a container has been defined that will render above the footer.container container.

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <container name="custom.container" as="customContainer" label="Custom Container" htmlTag="div" before="footer.container" htmlClass="row" />
    </body>
</xml>

The minimum requirements for defining a container is that the node should contain the name attribute. The additional attributes are not required, however they may be useful to use.

In order to specify whether your custom container should render before or after an existing container, it is essential to know the names of the containers that Magento defines by default.

You could by looking at the vendor/magento/module-theme/view/frontend/page_layout/1column.xml file, which defines three containers: header.container, page.top and footer.container while referencing a page.wrapper container.

<?xml version="1.0"?>
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_layout.xsd">
    <update handle="empty"/>
    <referenceContainer name="page.wrapper">
        <container name="header.container" as="header_container" label="Page Header Container" htmlTag="header" htmlClass="page-header" before="main.content"/>
        <container name="page.top" as="page_top" label="After Page Header" after="header.container"/>
        <container name="footer-container" as="footer" before="before.body.end" label="Page Footer Container" htmlTag="footer" htmlClass="page-footer"/>
    </referenceContainer>
</layout>

The vendor/magento/module-theme/view/base/page_layout/empty.xml also contains some useful container names.

<?xml version="1.0"?>
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_layout.xsd">
    <container name="root">
        <container name="after.body.start" as="after.body.start" before="-" label="Page Top"/>
        <container name="page.wrapper" as="page_wrapper" htmlTag="div" htmlClass="page-wrapper">
            <container name="global.notices" as="global_notices" before="-"/>
            <container name="main.content" htmlTag="main" htmlId="maincontent" htmlClass="page-main">
                <container name="columns.top" label="Before Main Columns"/>
                <container name="columns" htmlTag="div" htmlClass="columns">
                    <container name="main" label="Main Content Container" htmlTag="div" htmlClass="column main"/>
                </container>
            </container>
            <container name="page.bottom.container" as="page_bottom_container" label="Before Page Footer Container" after="main.content" htmlTag="div" htmlClass="page-bottom"/>
            <container name="before.body.end" as="before_body_end" after="-" label="Page Bottom"/>
        </container>
    </container>
</layout>

One advantage of containers in Magento 2 over the structural blocks used in Magento is that within Magento 2, you do not have to add any further instructions to get the container to render (like using $this->getChildHtml() within the template’s .phtml file in M1).

With that said, your container will need some actual content within it in order for Magento to use the container within the page layout.

For example, to define a block within the container, you could write the following.

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <container name="custom.container" as="customContainer" label="Custom Container" htmlTag="div" before="footer.container" htmlClass="row">
            <block class="Magento\Framework\View\Element\Template" name="yourtheme.block.name" before="-" template="Magento_Theme::page/page.phtml"/>
        </container>
    </body>
</page>

You’ll then have some content within your container that Magento will render wherever you specify.

Define an Empty Container?

If you need to include an empty container for whatever reason, you could define a block which has a class of Magento\Framework\View\Element\Text. Then, include a text argument that includes an empty HTML comment.

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <container name="custom.container" as="customContainer" label="Custom Container" htmlTag="div" before="footer.container" htmlClass="row">
            <block class="Magento\Framework\View\Element\Text" name="comment.placeholder">
                <arguments>
                    <argument name="text" xsi:type="string"><![CDATA[<!-- -->]]></argument>
                </arguments>
            </block>
        </container>
    </body>
</page>

Similarly, you could use <![CDATA[ ]]> in place of the empty HTML comment. Not the cleanest solution, but one that will render an empty container that you need.

Note: This article is based on Magento Open Source version 2.2.