PanelMenu

PanelMenu is a hybrid of accordion-tree components.


import PanelMenu from 'primevue/panelmenu';

PanelMenu requires a collection of menuitems as its model.


<PanelMenu :model="items" />

Only one root menuitem at a time can be active by default, enabling multiple property changes this behavior to allow multiple root menuitems.


<PanelMenu :model="items" multiple />

If the menuitem has a key defined, PanelMenu state can be controlled programmatically with the expandedKeys property that defines the keys that are expanded. This property is a Map instance whose key is the key of a node and value is a boolean.


<Button type="button" label="Toggle All" text @click="toggleAll" />
<PanelMenu v-model:expandedKeys="expandedKeys" :model="items" />

PanelMenu offers item customization with the item template that receives the menuitem instance from the model as a parameter.


<PanelMenu :model="items">
    <template #item="{ item }">
        <a v-ripple class="flex align-items-center px-3 py-2 cursor-pointer">
            <span :class="[item.icon, 'text-primary']" />
            <span :class="['ml-2', { 'font-semibold': item.items }]">{{ item.label }}</span>
            <Badge v-if="item.badge" class="ml-auto" :value="item.badge" />
            <span v-if="item.shortcut" class="ml-auto border-1 surface-border border-round surface-100 text-xs p-1">{{ item.shortcut }}</span>
        </a>
    </template>
</PanelMenu>

The command property defines the callback to run when an item is activated by click or a key event.


<PanelMenu :model="items" />
<Toast />

Items with navigation are defined with templating to be able to use a router link component, an external link or programmatic navigation.


<PanelMenu :model="items">
    <template #item="{ item }">
        <router-link v-if="item.route" v-slot="{ href, navigate }" :to="item.route" custom>
            <a v-ripple class="flex align-items-center cursor-pointer text-color px-3 py-2" :href="href" @click="navigate">
                <span :class="item.icon" />
                <span class="ml-2 text-color">{{ item.label }}</span>
            </a>
        </router-link>
        <a v-else v-ripple class="flex align-items-center cursor-pointer text-color px-3 py-2" :href="item.url" :target="item.target">
            <span :class="item.icon" />
            <span class="ml-2">{{ item.label }}</span>
            <span v-if="item.items" class="pi pi-angle-down text-primary ml-auto" />
        </a>
    </template>
</PanelMenu>

Screen Reader

Accordion header elements have a button role, an aria-label defined using the label property of the menuitem model and aria-controls to define the id of the content section along with aria-expanded for the visibility state.

The content of an accordion panel uses region role, defines an id that matches the aria-controls of the header and aria-labelledby referring to the id of the header.

The tree elements has a tree as the role and each menu item has a treeitem role along with aria-label and aria-expanded attributes. The container element of a treenode has the group role. The aria-setsize, aria-posinset and aria-level attributes are calculated implicitly and added to each treeitem.

Header Keyboard Support

KeyFunction
tabMoves focus to the next the focusable element in the page tab sequence.
shift + tabMoves focus to the previous the focusable element in the page tab sequence.
enterToggles the visibility of the content.
spaceToggles the visibility of the content.
down arrowMoves focus to the next header. If focus is on the last header, moves focus to the first header.
up arrowMoves focus to the previous header. If focus is on the first header, moves focus to the last header.
homeMoves focus to the first header.
endMoves focus to the last header.