OpenCms allows you to nest containers. You can use the <cms:container> tag in formatter JSPs. Then content elements placed on your webpage add new containers. Here you know what you should know when using nested containers.

What are nested containers?

Containers are holes in a template where content can be dropped. When writing a template JSP in OpenCms, you use the <cms:container> tag to add such holes. See here to find out how to write a template JSP. Nested containers are also such holes where content can be dropped. But they are not defined in the template JSP. They are defined in a content's formatter. If you add a content rendered by such a formatter to your page, it will make up a new container inside of the container where you place the content. Hence, a nested container. To distinguish nested containers from the containers defined in a template, we call the later ones top-level containers.

Nested containers are not part of the content itself. If you place the content that renders the nested container a second time on your page, or on a different page, the elements in the nested container will not be inserted. For each element-instance of the content that renders the nested container, the container is completely independent.

Nested containers are tight to a container page element. If you move a content that renders a nested container on a page (and the formatter does not change), the element in the nested container will move with it. If you remove the content, or change its formatter, the nested container will vanish and its elements are not visible anymore.

Use cases for nested containers

Nested container have various application:

  • Tab elements where each tab can hold different contents,
  • Flexible template design, by using "structure" contents to fix the page layout,
  • Fine-grained restrictions on where to put different content, e.g., allowing content of some type only in nested containers.

If your focus is on grouping content, such that the whole group can be moved across and used in various pages, nested containers are not what you need. Use instead

Writing a formatter with nested containers

To expose a nested container via a formatter, use the <cms:container>-tag in the formatter. You can use the tag exactly like in a template JSP. There is only one detail you should know: In contrast to top-level containers, the name attribute of a nested container will not directly form the container's name. This is necessary to keep container names unique at a page, even if two formatters add containers with the same name attribute.

You should take care that each container rendered by your formatter has a unique name inside your formatter. This is for example relevant when you design a tab element with a varying number of tabs, each tab having an own container. Here's an example of a formatter for such a tab element.

<%@page buffer="none" session="false" trimDirectiveWhitespaces="true" taglibs="c,cms" %>

<cms:formatter var="content" val="value" rdfa="rdfa">

<div class="margin-bottom-30">
    <div class="tab-v1">
        <ul class="nav nav-tabs">

            <c:forEach var="label" items="${content.valueList.Label}" varStatus="status">
                <li class="${status.first? 'active':''}">
                    <a href="#${cms.element.instanceId}-tab-container${status.count}" 
                       data-toggle="tab">
                        ${label}
                    </a>
                </li>
            </c:forEach>

        </ul>

        <div class="tab-content">

            <c:forEach var="label" items="${content.valueList.Label}" varStatus="status">
                <cms:container name="tab-container${status.count}" 
                               type="content" tagClass="tab-pane ${status.first? 'active':''}">
                </cms:container>
            </c:forEach>

        </div><!--/tab-content-->
    </div><!--/tab-v1-->
</div>

</cms:formatter>

You should not miss two important details:

  • To keep the name attribute of the tab containers unique inside of the formatter, the ${status.count} property is used inside the second <c:forEach> loop.
  • The id attribute of the HTML element rendered for the container tag is {element id}-{name attribute}, as seen from the first <c:forEach> loop where the id is needed to implement tab switching. The id is also the container's name you can retrieve for example by using ${cms.container.name} inside of the container.

A tab element using nested containers is found in the OpenCms demo website here.

3.1 Configuring formatters with nested containers

When configuring a formatter that exposes a nested container, you should check the option "Nested containers" in the formatter configuration. Your formatter might work also without checking this option, but this could not be the case in future OpenCms versions. Besides that fact, the option will cause some extra validations.

Technical details

Nested containers are similar to normal containers managed by the container page. When a content that exposes a nested container is added to a page, the container will be stored similar to a top-level container in the container page. The only additional information is the element id of the container's parent element, i.e., the id of the container page element that represents the content you just placed on the page. Have a look into a container page that holds information about a nested container to see the details.

When an element that exposed a nested container is removed from a page, also the information about the nested container is removed from the container page.