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.
{# 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 %}
{% 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") },
},
},
} %}
<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.