Side Nav
The side navigation provides a consistent, easy-to-scan way for users to move through major sections of an application. It stays visible as users browse, giving them a clear understanding of where they are and what options are available.
import {SideNavModule} from "@qualcomm-ui/angular/side-nav"Overview
The side nav is an extension of our tree component.
- The Side Navigation relies on the
TreeCollectionclass to manage its items. Refer to the API below for details. - Like with the tree, Side Navigations are composed of nodes, which are objects that describe the navigation data. There are two types of nodes:
- A
branchnode has children. - A
leafnode does not have any children.
- A
- Each node has a
value(unique identifier used for expansion) and atext(display text).
Default object shape:
value(required): unique identifier for expansion/selectiontext(required): display textnodes(optional): child nodes for branchesdisabled(optional): prevents interaction whentrue
These keys can be customized via the TreeCollection constructor.
Examples
Node Shorthand
We expose the <q-side-nav-nodes> shorthand for rendering nested nodes. Use the following directives to customize the tree nodes:
<ng-template
let-branch
q-side-nav-branch-template
[rootNode]="collection.rootNode"
>
<div q-side-nav-branch-node>
<!-- ... -->
</div>
</ng-template>Note that <q-side-nav-nodes> automatically renders child nodes for branches, so you only have to customize the content of the node itself.
<div q-side-nav-root [collection]="collection">
<div q-side-nav-header>
<div q-side-nav-header-logo>
<q-logo />
</div>
<div q-side-nav-header-title>Qualcomm</div>
</div>
@for (
node of collection.rootNode.nodes;
let i = $index;
track collection.getNodeValue(node)
) {
<q-side-nav-nodes [indexPath]="[i]" [node]="node">
<ng-template
let-branch
q-side-nav-branch-template
[rootNode]="collection.rootNode"
>
<div q-side-nav-branch-node>
@if (branch.node.icon) {
<svg q-side-nav-node-icon [qIcon]="branch.node.icon"></svg>
}
<span q-side-nav-node-text>{{ branch.node.text }}</span>
<div q-side-nav-branch-trigger></div>
</div>
</ng-template>
<ng-template
let-leaf
q-side-nav-leaf-template
[rootNode]="collection.rootNode"
>
<div q-side-nav-leaf-node>
<div q-side-nav-node-indicator></div>
@if (leaf.node.icon) {
<svg q-side-nav-node-icon [qIcon]="leaf.node.icon"></svg>
}
<span q-side-nav-node-text>{{ leaf.node.text }}</span>
</div>
</ng-template>
</q-side-nav-nodes>
}
</div>
Node Types
Pass the rootNode input to the template directives to enable TypeScript type inference. This allows branch.node and leaf.node to have your custom node type instead of the generic TreeNode type.
Grouping
Group nodes using the collection's groupChildren method. This should be called on the top-level node of your SideNav. Nested groups are not supported.
<div q-side-nav-root [collection]="collection">
<div q-side-nav-header>
<div q-side-nav-header-logo>
<q-logo />
</div>
<div q-side-nav-header-title>Qualcomm</div>
</div>
@for (group of groups; track group.key) {
<div q-side-nav-group>
<div q-side-nav-divider></div>
@if (group.key !== "ungrouped") {
<div q-side-nav-group-label>{{ group.key }}</div>
}
@for (
item of group.items;
track collection.getNodeValue(item.node)
) {
<q-side-nav-nodes [indexPath]="item.indexPath" [node]="item.node">
<ng-template
let-branch
q-side-nav-branch-template
[rootNode]="collection.rootNode"
>
<div q-side-nav-branch-node>
<div q-side-nav-node-indicator></div>
@if (branch.node.icon) {
<svg
q-side-nav-node-icon
[qIcon]="branch.node.icon"
></svg>
}
<span q-side-nav-node-text>{{ branch.node.text }}</span>
<div q-side-nav-branch-trigger></div>
</div>
</ng-template>
<ng-template
let-leaf
q-side-nav-leaf-template
[rootNode]="collection.rootNode"
>
<div q-side-nav-leaf-node>
<div q-side-nav-node-indicator></div>
@if (leaf.node.icon) {
<svg q-side-nav-node-icon [qIcon]="leaf.node.icon"></svg>
}
<span q-side-nav-node-text>{{ leaf.node.text }}</span>
</div>
</ng-template>
</q-side-nav-nodes>
}
</div>
}
</div>
Default Expanded
Expand nodes by default using the defaultExpandedValue input. Or use expandedValue and expandedValueChanged to control the expansion manually. These inputs follow our controlled state pattern.
<div
q-side-nav-root
[collection]="collection"
[defaultExpandedValue]="['account']"
>
Disabled Nodes
You can disable nodes by setting the disabled property on the node object.
import {Component} from "@angular/core"
import {
Bell,
CircleUser,
CreditCard,
LayoutDashboard,
Network,
ShieldCheck,
User,
} from "lucide-angular"
import {provideIcons} from "@qualcomm-ui/angular-core/lucide"
import {IconDirective} from "@qualcomm-ui/angular/icon"
import {SideNavModule} from "@qualcomm-ui/angular/side-nav"
import {createTreeCollection} from "@qualcomm-ui/core/tree"
import {QLogoComponent} from "./q-logo.component"
interface SideNavItem {
disabled?: boolean
icon?: string
id: string
nodes?: SideNavItem[]
text: string
}
const collection = createTreeCollection<SideNavItem>({
nodeChildren: "nodes",
nodeText: (node) => node.text,
nodeValue: (node) => node.id,
rootNode: {
id: "ROOT",
nodes: [
{
icon: "Bell",
id: "notifications",
text: "Notifications",
},
{
disabled: true,
icon: "LayoutDashboard",
id: "dashboard",
text: "Dashboard",
},
{
icon: "Network",
id: "ai-studio",
text: "AI Studio",
},
{
icon: "CircleUser",
id: "account",
nodes: [
{
icon: "User",
id: "profile",
text: "Profile",
},
{
icon: "ShieldCheck",
id: "security",
text: "Security",
},
{
icon: "CreditCard",
id: "billing",
text: "Billing",
},
],
text: "Account",
},
],
text: "",
},
})
@Component({
imports: [SideNavModule, IconDirective, QLogoComponent],
providers: [
provideIcons({
Bell,
CircleUser,
CreditCard,
LayoutDashboard,
Network,
ShieldCheck,
User,
}),
],
selector: "side-nav-disabled-node-demo",
template: `
<div class="flex justify-center">
<div
q-side-nav-root
[collection]="collection"
[defaultExpandedValue]="['account']"
>
<div q-side-nav-header>
<div q-side-nav-header-logo>
<q-logo />
</div>
<div q-side-nav-header-title>Qualcomm</div>
</div>
@for (
node of collection.rootNode.nodes;
let i = $index;
track collection.getNodeValue(node)
) {
<q-side-nav-nodes [indexPath]="[i]" [node]="node">
<ng-template
let-branch
q-side-nav-branch-template
[rootNode]="collection.rootNode"
>
<div q-side-nav-branch-node>
@if (branch.node.icon) {
<svg q-side-nav-node-icon [qIcon]="branch.node.icon"></svg>
}
<span q-side-nav-node-text>{{ branch.node.text }}</span>
<div q-side-nav-branch-trigger></div>
</div>
</ng-template>
<ng-template
let-leaf
q-side-nav-leaf-template
[rootNode]="collection.rootNode"
>
<div q-side-nav-leaf-node>
<div q-side-nav-node-indicator></div>
@if (leaf.node.icon) {
<svg q-side-nav-node-icon [qIcon]="leaf.node.icon"></svg>
}
<span q-side-nav-node-text>{{ leaf.node.text }}</span>
</div>
</ng-template>
</q-side-nav-nodes>
}
</div>
</div>
`,
})
export class SideNavDisabledNodeDemo {
collection = collection
}Collapsed
Side Nav can be collapsed to render only the top-level icons.
The open state of the panel can be controlled using the open, openChanged and defaultOpen inputs. These inputs follow our controlled state pattern.
<div
q-side-nav-root
[collection]="collection"
[open]="open()"
(openChanged)="open.set($event)"
>
<div q-side-nav-header>
<div q-side-nav-header-logo>
<q-logo />
</div>
<div q-side-nav-header-title>Qualcomm</div>
<button q-side-nav-collapse-trigger></button>
</div>
@for (
node of collection.rootNode.nodes;
let i = $index;
track collection.getNodeValue(node)
) {
<q-side-nav-nodes [indexPath]="[i]" [node]="node">
<ng-template
let-branch
q-side-nav-branch-template
[rootNode]="collection.rootNode"
>
<div q-side-nav-branch-node [attr.aria-label]="branch.node.text">
<div q-side-nav-node-indicator></div>
@if (branch.node.icon) {
<svg q-side-nav-node-icon [qIcon]="branch.node.icon"></svg>
}
<span q-side-nav-node-text>{{ branch.node.text }}</span>
<div q-side-nav-branch-trigger></div>
</div>
</ng-template>
<ng-template
let-leaf
q-side-nav-leaf-template
[rootNode]="collection.rootNode"
>
<div q-side-nav-leaf-node [attr.aria-label]="leaf.node.text">
<div q-side-nav-node-indicator></div>
@if (leaf.node.icon) {
<svg q-side-nav-node-icon [qIcon]="leaf.node.icon"></svg>
}
<span q-side-nav-node-text>{{ leaf.node.text }}</span>
</div>
</ng-template>
</q-side-nav-nodes>
}
</div>
Filtering
Here's an example that filters the items using matchSorter.
<div
q-side-nav-root
[collection]="collection()"
[expandedValue]="expanded()"
(expandedValueChanged)="expanded.set($event.expandedValue)"
>
<div q-side-nav-header>
<div q-side-nav-header-logo>
<q-logo />
</div>
<div q-side-nav-header-title>Qualcomm</div>
</div>
<hr q-side-nav-divider />
<q-text-input
aria-label="Search filter"
placeholder="Search"
q-side-nav-filter-input
size="sm"
startIcon="Search"
style="margin-bottom: 16px"
[ngModel]="query()"
(ngModelChange)="search($event)"
/>
@for (group of groups(); track group.key) {
<div q-side-nav-group>
<hr q-side-nav-divider />
@if (group.key !== "ungrouped") {
<div q-side-nav-group-label>{{ group.key }}</div>
}
@for (
item of group.items;
track collection().getNodeValue(item.node)
) {
<q-side-nav-nodes [indexPath]="item.indexPath" [node]="item.node">
<ng-template
let-branch
q-side-nav-branch-template
[rootNode]="collection().rootNode"
>
<div q-side-nav-branch-node>
@if (branch.node.icon) {
<svg
q-side-nav-node-icon
[qIcon]="branch.node.icon"
></svg>
}
<span q-side-nav-node-text>{{ branch.node.text }}</span>
<div q-side-nav-branch-trigger></div>
</div>
</ng-template>
<ng-template
let-leaf
q-side-nav-leaf-template
[rootNode]="collection().rootNode"
>
<div q-side-nav-leaf-node>
<div q-side-nav-node-indicator></div>
@if (leaf.node.icon) {
<svg q-side-nav-node-icon [qIcon]="leaf.node.icon"></svg>
}
<span q-side-nav-node-text>{{ leaf.node.text }}</span>
</div>
</ng-template>
</q-side-nav-nodes>
}
</div>
}
</div>
Links
Side Nav nodes can be links. Apply the q-side-nav-leaf-node directive to an anchor element with routerLink to create navigable links.
<a q-side-nav-leaf-node [routerLink]="leaf.node.pathname">
<div q-side-nav-node-indicator></div>
<span q-side-nav-node-text>{{ leaf.node.text }}</span>
</a>
Surface
Use the surface input to change the background color of the Side Nav.
import {Component} from "@angular/core"
import {provideIcons} from "@qualcomm-ui/angular-core/lucide"
import {IconDirective} from "@qualcomm-ui/angular/icon"
import {SideNavModule} from "@qualcomm-ui/angular/side-nav"
import {groupedCollection, groupedIcons} from "./grouped-items"
import {QLogoComponent} from "./q-logo.component"
@Component({
imports: [SideNavModule, IconDirective, QLogoComponent],
providers: [provideIcons(groupedIcons)],
selector: "side-nav-surface-demo",
template: `
<div class="flex justify-center">
<div q-side-nav-root surface="secondary" [collection]="collection">
<div q-side-nav-header>
<div q-side-nav-header-logo>
<q-logo />
</div>
<div q-side-nav-header-title>Qualcomm</div>
</div>
@for (group of groups; track group.key) {
<div q-side-nav-group>
<div q-side-nav-divider></div>
@if (group.key !== "ungrouped") {
<div q-side-nav-group-label>{{ group.key }}</div>
}
@for (
item of group.items;
track collection.getNodeValue(item.node)
) {
<q-side-nav-nodes [indexPath]="item.indexPath" [node]="item.node">
<ng-template
let-branch
q-side-nav-branch-template
[rootNode]="collection.rootNode"
>
<div q-side-nav-branch-node>
<div q-side-nav-node-indicator></div>
@if (branch.node.icon) {
<svg
q-side-nav-node-icon
[qIcon]="branch.node.icon"
></svg>
}
<span q-side-nav-node-text>{{ branch.node.text }}</span>
<div q-side-nav-branch-trigger></div>
</div>
</ng-template>
<ng-template
let-leaf
q-side-nav-leaf-template
[rootNode]="collection.rootNode"
>
<div q-side-nav-leaf-node>
<div q-side-nav-node-indicator></div>
@if (leaf.node.icon) {
<svg q-side-nav-node-icon [qIcon]="leaf.node.icon"></svg>
}
<span q-side-nav-node-text>{{ leaf.node.text }}</span>
</div>
</ng-template>
</q-side-nav-nodes>
}
</div>
}
</div>
</div>
`,
})
export class SideNavSurfaceDemo {
collection = groupedCollection
groups = this.collection.groupChildren(
[],
(node) => node.group ?? "ungrouped",
["ungrouped", "Main menu"],
)
}Tooltips
Consider wrapping collapsed nodes with the Tooltip component to provide context about each item. This is also useful for describing disabled nodes.
<div q-tooltip>
<span q-tooltip-trigger>
<div q-side-nav-leaf-node>
<div q-side-nav-node-indicator></div>
@if (leaf.node.icon) {
<svg q-side-nav-node-icon [qIcon]="leaf.node.icon"></svg>
}
<span q-side-nav-node-text>{{ leaf.node.text }}</span>
</div>
</span>
{{ leaf.node.tooltip || leaf.node.text }}
</div>
API
q-side-nav-root
string[]
stringbooleanstring[]
'ltr' | 'rtl'
booleanstring[]
booleanstring() =>
| Node
| ShadowRoot
| Document
stringboolean(details: {
indexPath: number[]
node: T
signal: AbortSignal
valuePath: string[]
}) => Promise<any[]>
booleanstring[]
| 'multiple'
| 'single'
(state: {
checked:
| boolean
| 'indeterminate'
depth: number
disabled: boolean
expanded: boolean
focused: boolean
id: string
indexPath: number[]
isBranch: boolean
loading: boolean
node: T
selected: boolean
textId: string
value: string
valuePath: string[]
}) => boolean
| 'primary'
| 'secondary'
booleanboolean{
expandedNodes: Array<T>
expandedValue: string[]
focusedValue: string
}
{
focusedNode: T
focusedValue: string
}
{
collection: TreeCollection<T>
}
{
nodes: NodeWithError[]
}
boolean{
focusedValue: string
selectedNodes: Array<T>
selectedValue: string[]
}
class'qui-side-nav__root'data-surface| 'primary'
| 'secondary'
data-tree-part'root'tabIndex-1
q-side-nav-nodes
number[]
TTemplateRef<any>
TemplateRef<any>
booleanTreeCollection
Note that the TreeCollection accepts a single generic type parameter, T, which is the object type of the node used in the collection.
Constructor
The constructor of the TreeCollection class accepts the following options:
keyof T
(
node: T,
) => number
| keyof T
| ((node: T) => boolean)
| keyof T
| ((node: T) => string)
| keyof T
| ((node: T) => string)
T(
indexPath: number[],
) => T
- indexPath:Array of indices representing the path to the node
(
parentIndexPath: number[],
valueIndexPath: number[],
) => boolean
- parentIndexPath:The parent path
- valueIndexPath:The child path to check
(
rootNode: T,
) => any
- rootNode:The new root node for the copied collection
(
predicate: (
node: T,
indexPath: number[],
) => boolean,
) => any
- predicate:Function to test each node
(
value: string,
rootNode?: T,
) => T
- value:The value to search for
- rootNode:The root node to start searching from
(
predicate: (
node: T,
indexPath: number[],
) => boolean,
rootNode?: T,
) => T
(
values: string[],
rootNode?: T,
) => Array<T>
- values:Array of values to search for
- rootNode:The root node to start searching from
(
rootNode?: T,
) => Array<
T & {
_children: number[]
_index: number
_parent: number
}
>
- rootNode:The root node to start flattening from
(
rootNode?: T,
opts?: {
skip?: (args: {
indexPath: number[]
node: T
value: string
}) => boolean | void
} & {
depth?:
| number
| ((
nodeDepth: number,
) => boolean)
},
) => string[]
- rootNode:The root node to start from
- opts:Options for skipping nodes and filtering by depth
(
value: string,
) => number
- value:The value to find the depth for
(
valueOrIndexPath?:
| string
| number[],
options?: T & {
disabled?: boolean
id?: string
onUnregister?: (
index: number,
) => void
requireContext?: boolean
},
) => Array<T>
- valueOrIndexPath:Either a node value or index path
- options:Options for controlling which descendants to include
(
valueOrIndexPath:
| string
| number[],
options?: T & {
disabled?: boolean
id?: string
onUnregister?: (
index: number,
) => void
requireContext?: boolean
},
) => string[]
- valueOrIndexPath:Either a node value or index path
- options:Options for controlling which descendants to include
(
rootNode?: T,
) => T
- rootNode:The root node to start searching from
(
value: string,
) => number[]
- value:The value to find the index path for
(
rootNode?: T,
opts?: {
skip?: (args: {
indexPath: number[]
node: T
value: string
}) => boolean | void
},
) => T
- rootNode:The root node to start searching from
- opts:Options for skipping nodes during traversal
(
value: string,
opts?: {
skip?: (args: {
indexPath: number[]
node: T
value: string
}) => boolean | void
},
) => T
- value:The value to find the next node from
- opts:Options for skipping nodes during traversal
(
indexPath: number[],
) => T
- indexPath:Array of indices representing the path to the node
(
node: T,
) => Array<T>
(
node: T,
) => number
- node:The node to get children count for
(
node: T,
) => boolean
- node:The node to check
(
node: T,
) => string
- node:The node to get the value from
(
valueOrIndexPath:
| string
| number[],
) => T
- valueOrIndexPath:Either a node value or index path
(
valueOrIndexPath:
| string
| number[],
) => Array<T>
- valueOrIndexPath:Either a node value or index path
(
value: string,
opts?: {
skip?: (args: {
indexPath: number[]
node: T
value: string
}) => boolean | void
},
) => T
- value:The value to find the previous node from
- opts:Options for skipping nodes during traversal
(
indexPath: number[],
) => T
- indexPath:Array of indices representing the path to the node
(
indexPath: number[],
) => Array<T>
- indexPath:Array of indices representing the path to the node
(
indexPath: number[],
) => string
- indexPath:Array of indices representing the path to the node
(
indexPath: number[],
) => string[]
- indexPath:Array of indices representing the path to the node
(
rootNode?: T,
) => string[]
- rootNode:The root node to start from
(
parentIndexPath: IndexPath,
groupBy: (
node: T,
index: number,
) => string,
sortGroups?:
| string[]
| ((
a: {
items: Array<{
indexPath: IndexPath
node: T
}>
key: string
},
b: {
items: Array<{
indexPath: IndexPath
node: T
}>
key: string
},
) => number),
) => GroupedTreeNode<T>[]
- parentIndexPath:Index path of the parent node whose children to group. Pass
[]for root-level children. - groupBy:Function that determines the group key for each child node
- sortGroups:Optional array of group keys defining order, or comparator function to sort the groups. By default, groups are sorted by first occurrence in the tree (insertion order)
// Group root-level children
const groups = collection.groupChildren([], (node) => node.group ?? 'default')
// Group with explicit order
const groups = collection.groupChildren(
[],
(node) => node.group,
['primary', 'secondary', 'tertiary']
)
// Group with custom sorter
const groups = collection.groupChildren(
[],
(node) => node.group,
(a, b) => String(a.key).localeCompare(String(b.key))
)
(
indexPath: number[],
nodes: Array<T>,
) => any
- indexPath:Array of indices representing the insertion point
- nodes:Array of nodes to insert
(
indexPath: number[],
nodes: Array<T>,
) => any
- indexPath:Array of indices representing the insertion point
- nodes:Array of nodes to insert
(
node: T,
) => boolean
- node:The node to check
(
other: TreeCollection<T>,
) => boolean
- other:The other tree collection to compare with
(
node: T,
) => boolean
- node:The node to check
(
node: T,
other: T,
) => boolean
- node:First node to compare
- other:Second node to compare
(
fromIndexPaths: Array<
number[]
>,
toIndexPath: number[],
) => any
- fromIndexPaths:Array of index paths to move from
- toIndexPath:Index path to move to
(
indexPaths: Array<number[]>,
) => any
- indexPaths:Array of index paths to remove
(
indexPath: number[],
node: T,
) => any
- indexPath:Array of indices representing the path to the node
- node:The new node to replace with
(
indexPath: number[],
children: Array<T>,
) => any
- indexPath:Array of indices representing the path to the node
- children:Array of child nodes to set on the target node
T(
values: string[],
) => string[]
- values:Array of values to sort
(
value: string,
) => string
(
T,
) => string
node.text, or node.value if node.text is not available.() => string[]
(opts: {
onEnter?: (
node: T,
indexPath: number[],
) => void | 'skip' | 'stop'
onLeave?: (
node: T,
indexPath: number[],
) => void | 'stop'
reuseIndexPath?: boolean
skip?: (args: {
indexPath: number[]
node: T
value: string
}) => boolean | void
}) => void
- opts:Options for visiting nodes, including skip predicate
Element API
q-side-nav-header
class'qui-side-nav__header'data-side-nav-part'header'data-state| 'open'
| 'closed'
| 'closing'
q-side-nav-header-logo
class'qui-side-nav__header-logo'data-side-nav-part'header-logo'hiddenbooleanq-side-nav-header-title
class'qui-side-nav__header-title'data-side-nav-part'header-title'hiddenbooleanq-side-nav-header-action
class'qui-side-nav__header-action'data-side-nav-part'header-action'data-state| 'open'
| 'closed'
| 'closing'
q-side-nav-collapse-trigger
stringclass'qui-side-nav__collapse-trigger'data-disableddata-side-nav-part'trigger'data-state| 'open'
| 'closed'
| 'closing'
q-side-nav-group
class'qui-side-nav__group'q-side-nav-group-label
class'qui-side-nav__group-label'q-side-nav-divider
class'qui-side-nav__divider'q-side-nav-branch
class'qui-side-nav__branch-root'data-branchstringdata-depthnumberdata-disableddata-loadingdata-ownedbystringdata-pathstringdata-selecteddata-state| 'open'
| 'closed'
data-tree-part'branch'data-valuestringhiddenbooleanstyleq-side-nav-branch-node
class'qui-side-nav__node-root'data-depthnumberdata-disableddata-focusdata-loadingdata-pathstringdata-selecteddata-state| 'open'
| 'closed'
data-tree-part'branch-node'data-valuestringtabIndex-1 | 0
q-side-nav-branch-trigger
| LucideIconData
| string
class'qui-side-nav__branch-trigger'data-disableddata-loadingdata-state| 'open'
| 'closed'
data-tree-part'branch-trigger'data-valuestringq-side-nav-branch-content
stringclass'qui-side-nav__branch-content'data-depthnumberdata-pathstringdata-tree-part'branch-content'data-valuestringq-side-nav-branch-indent-guide
q-side-nav-leaf-node
class'qui-side-nav__node-root'data-depthnumberdata-disableddata-focusdata-ownedbystringdata-pathstringdata-selecteddata-tree-part'leaf-node'data-valuestringhiddenbooleanstyletabIndex-1 | 0
q-side-nav-node-icon
class'qui-side-nav__node-icon'data-disableddata-focusdata-selecteddata-tree-part'node-icon'q-side-nav-node-text
data-disableddata-focusdata-selecteddata-tree-part'node-text'q-side-nav-node-indicator
class'qui-side-nav__node-indicator'data-disableddata-focusdata-selecteddata-tree-part'node-indicator'hiddenbooleanq-side-nav-node-action
class'qui-side-nav__node-action'data-disableddata-focusdata-selecteddata-tree-part'node-action'q-side-nav-node-accessory
class'qui-side-nav__node-accessory'q-side-nav-filter-input
class'qui-side-nav__filter-input'Template Directives
q-side-nav-branch-template
Tq-side-nav-leaf-template
ng-template to customize how leaf nodes (nodes
without children) are displayed.<ng-template q-side-nav-leaf-template let-node>
<div q-side-nav-leaf-node>
<span q-side-nav-node-text>{{ node.item.label }}</span>
</div>
</ng-template>
TUse this directive on an ng-template to customize the rendering of leaf nodes within q-side-nav-nodes.
ng-templateto customize how branch nodes (nodes with children) are displayed. Note that this template will only customize the content of the node. The parent<q-side-nav-nodes>component renders the branch children internally.