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 {SideNav} from "@qualcomm-ui/react/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 SideNav. There are two types of nodes:
- A
branchnode has children. - A
leafnode does not have any children. - 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 <SideNav.Nodes> shorthand for rendering nodes. Use its renderBranch and renderLeaf render props to customize the content of each tree node.
Note that <SideNav.Nodes> automatically renders child nodes for branches, so you only have to customize the content of the node itself.
import {SideNav} from "@qualcomm-ui/react/side-nav"
import {collection} from "./items"
import {QLogo} from "./q-logo"
export function SideNavNodeShorthandDemo() {
return (
<div className="flex justify-center">
<SideNav.Root collection={collection}>
<SideNav.Header>
<SideNav.HeaderLogo>
<QLogo />
</SideNav.HeaderLogo>
<SideNav.HeaderTitle>Qualcomm</SideNav.HeaderTitle>
</SideNav.Header>
{collection.rootNode.nodes?.map((parentNode, index) => (
<SideNav.Nodes
key={collection.getNodeValue(parentNode)}
indexPath={[index]}
node={parentNode}
renderBranch={({node}) => (
<SideNav.BranchNode>
{node.icon ? <SideNav.NodeIcon icon={node.icon} /> : null}
<SideNav.NodeText>{node.text}</SideNav.NodeText>
<SideNav.BranchTrigger />
</SideNav.BranchNode>
)}
renderLeaf={({node}) => (
<SideNav.LeafNode>
<SideNav.NodeIndicator />
{node.icon ? <SideNav.NodeIcon icon={node.icon} /> : null}
<SideNav.NodeText>{node.text}</SideNav.NodeText>
</SideNav.LeafNode>
)}
/>
))}
</SideNav.Root>
</div>
)
}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.
import {SideNav} from "@qualcomm-ui/react/side-nav"
import {collection} from "./grouped-items"
import {QLogo} from "./q-logo"
export function SideNavGroupsDemo() {
return (
<div className="flex justify-center">
<SideNav.Root collection={collection}>
<SideNav.Header>
<SideNav.HeaderLogo>
<QLogo />
</SideNav.HeaderLogo>
<SideNav.HeaderTitle>Qualcomm</SideNav.HeaderTitle>
</SideNav.Header>
{collection
.groupChildren([], (node) => node.group ?? "ungrouped", [
"ungrouped",
"Main menu",
])
.map((group) => (
<SideNav.Group key={group.key}>
<SideNav.Divider />
{group.key === "ungrouped" ? null : (
<SideNav.GroupLabel>{group.key}</SideNav.GroupLabel>
)}
{group.items.map(({indexPath, node}) => (
<SideNav.Nodes
key={collection.getNodeValue(node)}
indexPath={indexPath}
node={node}
renderBranch={({node}) => (
<SideNav.BranchNode>
<SideNav.NodeIndicator />
{node.icon ? <SideNav.NodeIcon icon={node.icon} /> : null}
<SideNav.NodeText>{node.text}</SideNav.NodeText>
<SideNav.BranchTrigger />
</SideNav.BranchNode>
)}
renderLeaf={({node}) => (
<SideNav.LeafNode>
<SideNav.NodeIndicator />
{node.icon ? <SideNav.NodeIcon icon={node.icon} /> : null}
<SideNav.NodeText>{node.text}</SideNav.NodeText>
</SideNav.LeafNode>
)}
/>
))}
</SideNav.Group>
))}
</SideNav.Root>
</div>
)
}Default Expanded
Expand nodes by default using the defaultExpandedValue prop. Or use expandedValue and onExpandedChange to control the expansion manually. These props follow our controlled state pattern.
<SideNav.Root collection={collection} defaultExpandedValue={["account"]}>
Disabled Nodes
You can disable nodes by setting the disabled property on the node object.
import {
Bell,
CircleUser,
CreditCard,
LayoutDashboard,
Network,
ShieldCheck,
User,
} from "lucide-react"
import {createTreeCollection} from "@qualcomm-ui/core/tree"
import {SideNav} from "@qualcomm-ui/react/side-nav"
import type {LucideIconOrElement} from "@qualcomm-ui/react-core/lucide"
import {QLogo} from "./q-logo"
interface SideNavItem {
disabled?: boolean
group?: string
icon?: LucideIconOrElement
id: string
nodes?: SideNavItem[]
text: string
}
const collection = createTreeCollection<SideNavItem>({
nodeChildren: "nodes",
nodeText: (node) => node.text,
nodeValue: (node) => node.id,
rootNode: {
id: "ROOT",
text: "",
nodes: [
{
icon: Bell,
id: "notifications",
text: "Notifications",
},
{
icon: LayoutDashboard,
id: "dashboard",
text: "Dashboard",
disabled: true,
},
{
icon: Network,
id: "ai-studio",
text: "AI Studio",
},
{
icon: CircleUser,
id: "account",
text: "Account",
nodes: [
{
icon: User,
id: "profile",
text: "Profile",
},
{
icon: ShieldCheck,
id: "security",
text: "Security",
},
{
icon: CreditCard,
id: "billing",
text: "Billing",
},
],
},
],
},
})
export function SideNavDisabledNodeDemo() {
return (
<div className="flex justify-center">
<SideNav.Root collection={collection} defaultExpandedValue={["account"]}>
<SideNav.Header>
<SideNav.HeaderLogo>
<QLogo />
</SideNav.HeaderLogo>
<SideNav.HeaderTitle>Qualcomm</SideNav.HeaderTitle>
</SideNav.Header>
{collection.rootNode.nodes?.map((parentNode, index) => (
<SideNav.Nodes
key={collection.getNodeValue(parentNode)}
indexPath={[index]}
node={parentNode}
renderBranch={({node}) => (
<SideNav.BranchNode>
{node.icon ? <SideNav.NodeIcon icon={node.icon} /> : null}
<SideNav.NodeText>{node.text}</SideNav.NodeText>
<SideNav.BranchTrigger />
</SideNav.BranchNode>
)}
renderLeaf={({node}) => (
<SideNav.LeafNode>
<SideNav.NodeIndicator />
{node.icon ? <SideNav.NodeIcon icon={node.icon} /> : null}
<SideNav.NodeText>{node.text}</SideNav.NodeText>
</SideNav.LeafNode>
)}
/>
))}
</SideNav.Root>
</div>
)
}Filtering
Here's an example that filters the items using matchSorter.
import {useState} from "react"
import {SideNav} from "@qualcomm-ui/react/side-nav"
import type {TreeCollection} from "@qualcomm-ui/utils/collection"
import {matchSorter} from "@qualcomm-ui/utils/match-sorter"
import {
collection as initialCollection,
type SideNavItem,
} from "./grouped-items"
import {QLogo} from "./q-logo"
export function SideNavFilteringDemo() {
const [collection, setCollection] =
useState<TreeCollection<SideNavItem>>(initialCollection)
const [expandedValue, setExpandedValue] = useState<string[]>([])
const [query, setQuery] = useState<string>("")
const search = (value: string) => {
setQuery(value)
if (!value) {
setCollection(initialCollection)
return
}
const nodes = matchSorter<SideNavItem>(
initialCollection.getDescendantNodes(),
value,
{
keys: [
"group",
"text",
(item) => {
// also include children of grouped items
return initialCollection
.getParentNodes(item.id)
.map((node) => node.group)
.filter(Boolean) as string[]
},
],
},
)
const nextCollection = initialCollection.filter((node) =>
nodes.some((n) => n.id === node.id),
)
setCollection(nextCollection)
setExpandedValue(nextCollection.getBranchValues())
}
return (
<div className="flex justify-center">
<SideNav.Root
collection={collection}
expandedValue={expandedValue}
onExpandedValueChange={(details) =>
setExpandedValue(details.expandedValue)
}
>
<SideNav.Header>
<SideNav.HeaderLogo>
<QLogo />
</SideNav.HeaderLogo>
<SideNav.HeaderTitle>Qualcomm</SideNav.HeaderTitle>
</SideNav.Header>
<SideNav.Divider />
<SideNav.FilterInput
className="mb-4"
onValueChange={search}
value={query}
/>
{collection
.groupChildren([], (node) => node.group ?? "ungrouped", [
"ungrouped",
"Main menu",
])
.map((group) => (
<SideNav.Group key={group.key}>
<SideNav.Divider />
{group.key === "ungrouped" ? null : (
<SideNav.GroupLabel>{group.key}</SideNav.GroupLabel>
)}
{group.items.map(({indexPath, node}) => (
<SideNav.Nodes
key={collection.getNodeValue(node)}
indexPath={indexPath}
node={node}
renderBranch={({node}) => (
<SideNav.BranchNode>
{node.icon ? <SideNav.NodeIcon icon={node.icon} /> : null}
<SideNav.NodeText>{node.text}</SideNav.NodeText>
<SideNav.BranchTrigger />
</SideNav.BranchNode>
)}
renderLeaf={({node}) => (
<SideNav.LeafNode>
<SideNav.NodeIndicator />
{node.icon ? <SideNav.NodeIcon icon={node.icon} /> : null}
<SideNav.NodeText>{node.text}</SideNav.NodeText>
</SideNav.LeafNode>
)}
/>
))}
</SideNav.Group>
))}
</SideNav.Root>
</div>
)
}Links
Side Nav nodes can be links using polymorphic composition. Use the render prop on the <SideNav.LeafNode> to specify the element type.
<SideNav.LeafNode
render={node.pathname ? <Link to={node.pathname} /> : <div />}
>
<SideNav.NodeIndicator />
{node.icon ? <SideNav.NodeIcon icon={node.icon} /> : null}
<SideNav.NodeText>{node.text}</SideNav.NodeText>
</SideNav.LeafNode>
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, onOpenChange and defaultOpen props. These props follow our controlled state pattern.
import {useState} from "react"
import {SideNav} from "@qualcomm-ui/react/side-nav"
import {collection} from "./grouped-items"
import {QLogo} from "./q-logo"
export function SideNavCollapsedDemo() {
const [open, setOpen] = useState<boolean>(false)
return (
<div className="flex w-full justify-start">
<SideNav.Root collection={collection} onOpenChange={setOpen} open={open}>
<SideNav.Header>
<SideNav.HeaderLogo>
<QLogo />
</SideNav.HeaderLogo>
<SideNav.HeaderTitle>Qualcomm</SideNav.HeaderTitle>
<SideNav.CollapseTrigger />
</SideNav.Header>
{collection
.groupChildren([], (node) => node.group ?? "ungrouped", [
"ungrouped",
"Main menu",
])
.map((group) => (
<SideNav.Group key={group.key}>
<SideNav.Divider />
{group.key === "ungrouped" ? null : (
<SideNav.GroupLabel>{group.key}</SideNav.GroupLabel>
)}
{group.items.map(({indexPath, node}) => (
<SideNav.Nodes
key={collection.getNodeValue(node)}
indexPath={indexPath}
node={node}
renderBranch={({node}) => (
<SideNav.BranchNode>
<SideNav.NodeIndicator />
{node.icon ? <SideNav.NodeIcon icon={node.icon} /> : null}
<SideNav.NodeText>{node.text}</SideNav.NodeText>
<SideNav.BranchTrigger />
</SideNav.BranchNode>
)}
renderLeaf={({node}) => (
<SideNav.LeafNode>
<SideNav.NodeIndicator />
{node.icon ? <SideNav.NodeIcon icon={node.icon} /> : null}
<SideNav.NodeText>{node.text}</SideNav.NodeText>
</SideNav.LeafNode>
)}
/>
))}
</SideNav.Group>
))}
</SideNav.Root>
</div>
)
}Tooltips
Consider wrapping collapsed nodes with the Tooltip component to provide context about each item. This is also useful for describing disabled nodes.
<Tooltip
trigger={
<span>
<SideNav.LeafNode>
<SideNav.NodeIndicator />
{node.icon ? (
<SideNav.NodeIcon icon={node.icon} />
) : null}
<SideNav.NodeText>{node.text}</SideNav.NodeText>
</SideNav.LeafNode>
</span>
}
>
{node.tooltip || node.text}
</Tooltip>
API
<SideNav.Root>
| Prop | Type | Default |
|---|---|---|
The tree collection data | ||
The initial expanded node ids when rendered.
Use when you don't need to control the expanded node value. | string[] | |
The initial focused node value when rendered.
Use when you don't need to control the focused node value. | string | |
The initial open state of the side navigation when rendered.
Use when you don't need to control the open state of the collapsible. | boolean | true |
The initial selected node value when rendered.
Use when you don't need to control the selected node value. | string[] | |
The document's text/writing direction. | 'ltr' | 'rtl' | 'ltr' |
Whether the collapsible is disabled. | boolean | |
The controlled expanded node ids | string[] | |
Whether clicking on a branch should open it or not | boolean | true |
The value of the focused node | string | |
A root node to correctly resolve document in custom environments. i.e.,
Iframes, Electron. | () => | |
id attribute. If
omitted, a unique identifier will be automatically generated for accessibility. | string | |
When true, the component will not be rendered in the DOM until it becomes
visible or active. | boolean | false |
Function to load children for a node asynchronously.
When provided, branches will wait for this promise to resolve before expanding. | (details: { | |
Called when the tree is opened or closed | (details: { | |
Called when the focused node changes | (details: { | |
Called when a node finishes loading children | (details: { | |
Called when loading children fails for one or more nodes | (details: { | |
Function invoked when the collapsible opens or closes
| ( | |
Called when the selection changes | (details: { | |
The controlled open state of the collapsible | boolean | |
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement | |
The controlled selected node value | string[] | |
Whether the tree supports multiple selection | | 'multiple' | 'single' |
Callback function that determines whether a node should be hidden. | ( | |
The background color of the side navigation. | | 'primary' | 'primary' |
Whether the tree supports typeahead search | boolean | true |
When true, the component will be completely removed from the DOM when it
becomes inactive or hidden, rather than just being hidden with CSS. | boolean | false |
string[]
stringbooleanstring[]
'ltr' | 'rtl'
booleanstring[]
booleanstring() =>
| Node
| ShadowRoot
| Document
stringboolean(details: {
indexPath: number[]
node: T
signal: AbortSignal
valuePath: string[]
}) => Promise<Array<T>>
(details: {
expandedNodes: Array<T>
expandedValue: string[]
focusedValue: string
}) => void
(details: {
focusedNode: T
focusedValue: string
}) => void
(details: {
collection: TreeCollection<T>
}) => void
(details: {
nodes: NodeWithError[]
}) => void
(
open: boolean,
) => void
- open:The next value.
(details: {
focusedValue: string
selectedNodes: Array<T>
selectedValue: string[]
}) => void
boolean| ReactElement
| ((
props: object,
) => ReactElement)
string[]
| 'multiple'
| 'single'
(
state: NodeState<T>,
) => boolean
| 'primary'
| 'secondary'
booleanboolean| Attribute / Property | Value |
|---|---|
className | 'qui-side-nav__root' |
data-part | 'root' |
data-scope | 'tree' |
data-surface | | 'primary' |
tabIndex | -1 |
className'qui-side-nav__root'data-part'root'data-scope'tree'data-surface| 'primary'
| 'secondary'
tabIndex-1
<SideNav.Nodes>
| Prop | Type | Default |
|---|---|---|
The index path of the tree node | number[] | |
node * The tree node to apply context from. | T | |
Render Prop
for the tree's branch items. Use this prop to supply the content of the branch
item like the text, indicator, or icon. | ||
Render Prop
for the tree's leaf items. Use this prop to supply the content of the leaf item
like the text, indicator, or icon. | ||
Props passed to the branch indent guide component. Only applicable when showIndentGuide is true. | TreeBranchIndentGuideProps | |
Whether to render the indent guide for branch child nodes. | boolean | false |
number[]
TTreeBranchIndentGuidePropsbooleanTreeCollection
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:
| Prop | Type | Default |
|---|---|---|
Property key for accessing a node's children. | keyof T | "nodes" |
Function to determine the count of a node's children. | ( | |
Property key or function to determine if a node is disabled. When a string key
is provided, the value of node[key] determines the disabled state. | | keyof T | "disabled" |
Property key or function for getting a node's text. When a string key
is provided, the value of node[key] is used. | | keyof T | "text" |
Property key or function for getting a node's value. When a string key
is provided, the value of node[key] is used. | | keyof T | "value" |
The root node of the tree | T |
keyof T
(
node: T,
) => number
| keyof T
| ((node: T) => boolean)
| keyof T
| ((node: T) => string)
| keyof T
| ((node: T) => string)
T| Prop | Type |
|---|---|
Gets the node at the specified index path.
| ( |
Checks if a parent index path contains a child index path.
| ( |
Creates a new tree collection with the same options but different root node.
| ( |
Filters the tree keeping only nodes that match the predicate.
| ( |
Finds the first node with the specified value.
| ( |
( | |
Finds all nodes with values matching the provided array.
| ( |
Flattens the tree into an array with parent/child relationships.
| ( |
Gets all branch node values with optional depth filtering.
| ( |
Gets the depth of a node with the specified value.
| ( |
Gets all descendant nodes of the specified node.
| ( |
Gets all descendant values of the specified node.
| ( |
Gets the first non-disabled node in the tree.
| ( |
Gets the index path for a node with the specified value.
| ( |
Gets the last non-disabled node in the tree.
| ( |
Gets the next node after the one with the specified value.
| ( |
Gets the next non-disabled sibling of the node at the index path.
| ( |
Returns all child nodes for this node.
Uses options.nodeToChildren if provided, otherwise falls back to default behavior. | ( |
Gets the number of children for a node, supporting lazy loading scenarios.
Uses options.nodeToChildrenCount if provided, otherwise falls back to default behavior.
| ( |
Checks if a node is disabled.
Uses options.isNodeDisabled if provided, otherwise falls back to default behavior.
| ( |
Gets the string value for a node.
Uses options.nodeValue if provided, otherwise falls back to default behavior.
| ( |
Gets the parent node of the specified node.
| ( |
Gets all parent nodes from root to the specified node.
| ( |
Gets the previous node before the one with the specified value.
| ( |
Gets the previous non-disabled sibling of the node at the index path.
| ( |
Gets all sibling nodes of the node at the index path.
| ( |
Gets the value of the node at the specified index path.
| ( |
Gets the path of values from root to the specified index path.
| ( |
Gets all values in the tree, excluding the root node.
| ( |
Groups children of a parent node by a specified key.
| ( |
// Group root-level children | |
Inserts nodes after the node at the specified index path.
| ( |
Inserts nodes before the node at the specified index path.
| ( |
Checks if a node is a branch node (has children or can have children).
| ( |
Compares this tree collection with another for deep equality.
| ( |
Checks if a node is the root node.
| ( |
Checks if two nodes are the same by comparing their values.
| ( |
Moves nodes from one location to another in the tree.
| ( |
Removes nodes at the specified index paths.
| ( |
Replaces the node at the specified index path.
| ( |
The root tree node. | T |
Sorts values according to their tree order.
| ( |
Converts a node value to its string representation.
| ( |
Converts a node to its string representation.
Uses options.nodeLabel if provided, otherwise falls back to default behavior: uses node.text, or node.value if node.text is not available.
| ( |
Serializes the tree to a JSON-compatible array of values. | () => string[] |
Visits all nodes in the tree with optional skip functionality.
| (opts: { |
(
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
T(
values: string[],
) => string[]
- values:Array of values to sort
(
value: string,
) => string
- value:The value to stringify
(
T,
) => string
node.text, or node.value if node.text is not available.- node:The node to stringify
() => 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
<SideNav.Group>
| Prop | Type |
|---|---|
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-side-nav__group' |
className'qui-side-nav__group'<SideNav.GroupLabel>
| Prop | Type |
|---|---|
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-side-nav__group-label' |
className'qui-side-nav__group-label'<SideNav.Divider>
| Prop | Type |
|---|---|
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-side-nav__divider' |
className'qui-side-nav__divider'<SideNav.Header>
| Prop | Type |
|---|---|
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-side-nav__header' |
className'qui-side-nav__header'<SideNav.HeaderLogo>
| Prop | Type |
|---|---|
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-side-nav__header-logo' |
className'qui-side-nav__header-logo'<SideNav.HeaderTitle>
| Prop | Type |
|---|---|
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-side-nav__header-title' |
className'qui-side-nav__header-title'<SideNav.HeaderAction>
| Prop | Type |
|---|---|
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-side-nav__header-action' |
className'qui-side-nav__header-action'<SideNav.Branch>
| Prop | Type |
|---|---|
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-side-nav__branch-root' |
data-branch | string |
data-depth | number |
data-disabled | |
data-loading | |
data-ownedby | string |
data-part | 'branch' |
data-path | string |
data-scope | 'tree' |
data-selected | |
data-state | | 'open' |
data-value | string |
hidden | boolean |
style |
className'qui-side-nav__branch-root'data-branchstringdata-depthnumberdata-disableddata-loadingdata-ownedbystringdata-part'branch'data-pathstringdata-scope'tree'data-selecteddata-state| 'open'
| 'closed'
data-valuestringhiddenbooleanstyle<SideNav.BranchNode>
<div> element by default.| Prop | Type |
|---|---|
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-side-nav__node-root' |
data-depth | number |
data-disabled | |
data-focus | |
data-loading | |
data-part | 'branch-node' |
data-path | string |
data-scope | 'tree' |
data-selected | |
data-state | | 'open' |
data-value | string |
tabIndex | -1 | 0 |
className'qui-side-nav__node-root'data-depthnumberdata-disableddata-focusdata-loadingdata-part'branch-node'data-pathstringdata-scope'tree'data-selecteddata-state| 'open'
| 'closed'
data-valuestringtabIndex-1 | 0
<SideNav.BranchTrigger>
<div>
element by default.| Prop | Type | Default |
|---|---|---|
The icon to display. This rotates by 180deg when the branch is expanded. | | LucideIcon | ChevronDown |
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
| LucideIcon
| ReactNode
| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-side-nav__branch-trigger' |
data-disabled | |
data-loading | |
data-part | 'branch-trigger' |
data-scope | 'tree' |
data-state | | 'open' |
data-value | string |
className'qui-side-nav__branch-trigger'data-disableddata-loadingdata-part'branch-trigger'data-scope'tree'data-state| 'open'
| 'closed'
data-valuestring<SideNav.BranchContent>
<div> element by
default.| Prop | Type |
|---|---|
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-side-nav__branch-content' |
data-depth | number |
data-part | 'branch-content' |
data-path | string |
data-scope | 'tree' |
data-value | string |
className'qui-side-nav__branch-content'data-depthnumberdata-part'branch-content'data-pathstringdata-scope'tree'data-valuestring<SideNav.BranchIndentGuide>
<div> element by default.| Prop | Type |
|---|---|
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-tree__branch-indent-guide' |
data-depth | number |
data-part | 'branch-indent-guide' |
data-scope | 'tree' |
style |
className'qui-tree__branch-indent-guide'data-depthnumberdata-part'branch-indent-guide'data-scope'tree'style<SideNav.LeafNode>
<div> element by default.| Prop | Type |
|---|---|
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-side-nav__node-root' |
data-depth | number |
data-disabled | |
data-focus | |
data-ownedby | string |
data-part | 'leaf-node' |
data-path | string |
data-scope | 'tree' |
data-selected | |
data-value | string |
hidden | boolean |
style | |
tabIndex | -1 | 0 |
className'qui-side-nav__node-root'data-depthnumberdata-disableddata-focusdata-ownedbystringdata-part'leaf-node'data-pathstringdata-scope'tree'data-selecteddata-valuestringhiddenbooleanstyletabIndex-1 | 0
<SideNav.NodeAction>
<button>
element by default.| Prop | Type | Default |
|---|---|---|
icon * Lucide icon to display inside the button. | | LucideIcon | |
The style variant of the button. Governs color.
TODO: link to design system docs. | | 'neutral' | 'neutral' |
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement | |
The size of the button and its icon. | | 'sm' | 'md' |
| LucideIcon
| ReactNode
| 'neutral'
| 'persistent-white'
| 'persistent-black'
| ReactElement
| ((
props: object,
) => ReactElement)
| 'sm'
| 'md'
| 'lg'
| Attribute / Property | Value |
|---|---|
className | 'qui-side-nav__node-action' |
data-disabled | |
data-focus | |
data-part | 'node-action' |
data-scope | 'tree' |
data-selected |
className'qui-side-nav__node-action'data-disableddata-focusdata-part'node-action'data-scope'tree'data-selected<SideNav.NodeIndicator>
<div> element by default.| Prop | Type |
|---|---|
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-side-nav__node-indicator' |
data-disabled | |
data-focus | |
data-part | 'node-indicator' |
data-scope | 'tree' |
data-selected | |
hidden | boolean |
className'qui-side-nav__node-indicator'data-disableddata-focusdata-part'node-indicator'data-scope'tree'data-selectedhiddenboolean<SideNav.NodeIcon>
<span> element by default.| Prop | Type |
|---|---|
icon * lucide-react icon or JSX Element. | | LucideIcon |
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
| LucideIcon
| ReactNode
| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-side-nav__node-icon' |
data-disabled | |
data-focus | |
data-part | 'node-icon' |
data-scope | 'tree' |
data-selected |
className'qui-side-nav__node-icon'data-disableddata-focusdata-part'node-icon'data-scope'tree'data-selected<SideNav.NodeProvider>
<SideNav.NodeText>
<span> element by default.| Prop | Type |
|---|---|
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
| ReactElement
| ((
props: object,
) => ReactElement)
TreeNodeText Bindings, QdsSideNavNodeTextBindings