cnc-nav-vertical
The sidebar tree: a vertical list of collapsible groups with icons and counts, nested to any
depth. Like the rest of the family it is a projection of one root tree.
Quick start
Give it a root tree and handle itemclick. Groups start collapsed
except along the path to active-id, so pointing that at a nested item opens its
ancestors.
nothing clicked yet
<cnc-nav-vertical
active-id="drafts"
@itemclick="router.go($event.detail.item.href)"
$root='{
"id": "root",
"children": [
{ "id": "dash", "label": "Dashboard", "icon": "heroicons/home", "href": "/" },
{ "id": "content", "label": "Content", "children": [
{ "id": "drafts", "label": "Drafts", "href": "/drafts", "count": 3 }
]}
]
}'
></cnc-nav-vertical>
Node fields
Every item in the tree, at any depth, takes the same fields.
| Field | Purpose |
|---|---|
| id |
The node's identity. Used by active-id and carried in the events, so it
must be unique across the whole tree rather than among its siblings.
|
| label | The text shown for the item. |
| children | An array of the same shape, nested to any depth. A node WITH children is a group; a node without is a destination. |
| href |
The destination. Note that the widget calls preventDefault() on it and
emits its event instead, so this is data for your handler rather than a working link.
|
| icon | An icon name shown before the label. |
| count | A number shown at the end of the row — unread items, results, whatever the row counts. Rendered only when TRUTHY, so a zero is omitted rather than shown. |
Usage guidance
Navigation is the HOST's job. Every one of these widgets swallows the click on an
href
and emits an event carrying it instead of letting the browser follow the link, so a nav with no
handler renders correctly and goes nowhere. Route from the event.
A group row both toggles and emits, so the handler sees clicks that are not destinations. Branch
on item.href rather than assuming every itemclick is a navigation, or
opening a section will route you somewhere.
Bind expanded when the sidebar is long. It is seeded once from
active-id
and then owned by the widget, so without a binding every collapse the user makes is lost on the
next page — which in a sidebar they see on every screen is the difference between a tree
they have arranged and one that keeps resetting.
Counts render only when truthy, so a zero disappears rather than showing "0". Where the distinction matters — an empty inbox against one you have not counted — put the value in the label instead.