Skip to content

Inner sidebar menus

Distinct from the dark global sidebar, many CP screens have a secondary nav in the left gutter — Settings, Utilities, and any plugin section with sub-pages. It sits transparently in the page margin (no card), and you build it by filling the layout’s sidebar block with the _includes/nav include.

Main content pane — the selected page renders here.
{# In your CP layout / template #}
{% block sidebar %}
    {% include "_includes/nav" with {
        label: "Settings"|t("my-plugin"),
        items: navItems,
        selectedItem: selectedNavItem,   {# a key from navItems #}
    } only %}
{% endblock %}
the items hash
{% set navItems = {
    general: { label: "General"|t("my-plugin"), url: url("my-plugin/general") },
    sites:   { label: "Sites"|t("my-plugin"),   url: url("my-plugin/sites") },

    {# A heading groups the items nested under it #}
    contentHeading: {
        heading: "Content"|t("my-plugin"),
        nested: {
            fields:   { label: "Fields",   url: url("my-plugin/fields") },
            sections: { label: "Sections", url: url("my-plugin/sections") },
        },
    },
} %}
HTML output
<nav aria-label="Settings">
  <ul>
    <li class="heading"><span>Content</span>
      <ul>
        <li><a class="sel" href="…" aria-current="page">Fields</a></li>
      </ul>
    </li>
  </ul>
</nav>
Key Purpose
label Link text for a nav item
url Destination (wrap in url())
heading + nested A section header with its own group of items below it
selected Force an item’s selected state (otherwise driven by selectedItem)

Note

Selection & accessibility. Pass selectedItem the key of the active page; the include adds class="sel" and aria-current="page" to the matching link. The selected link fills with --gray-500 and white text — the same treatment as the global sidebar — so the two nav levels feel consistent.

Note

Related: index sources. Element index screens use a similar left column, but built from sources (with counts, statuses, and nested groups) rather than plain links. If your plugin has an element index, define those in your element type’s defineSources() instead of hand-writing this nav.