Side navigation
A full-width nav rail that names its destinations in words: collapsible sections, one level of nesting, a brand header and a footer. The alternative to GdNavRail — reach for it when the destinations need saying rather than drawing.
Anatomy
Code
<GdSideNav :sections="nav" label="Components" width="268px" :brand="false" />Surface ground with a 1px right border. Items are 12.5px at weight 500; exactly one is active, in accent wash and accent ink at weight 600. Counts ride the row as a badge on the right, the same as a list row.
Sections & nesting
Everything that groups, discloses. A titled section head and a tree node are both a real <button aria-expanded>, and both put the chevron on the RIGHT, where a disclosure belongs.
A head is told from a node by its ICON, not by which side its chevron sits on — which is what frees both to put the disclosure where a disclosure belongs. Depth is carried by indentation alone: there are no tree lines, because with the heads marked by a glyph a rule down the side states a third time what the indent and the icon have already said.
- Whatever holds the current page opens itself, on load and on every navigation. A nav that hides where you are is worse than no nav.
- Navigating never slams a group shut behind you. The watcher only ever opens; closing is the user's.
- Sections start collapsed, so the rail opens compact rather than as a wall of every destination.
- One level of nesting, and that is a cap, not an omission. A nav needing three levels is describing an information-architecture problem the component should not make comfortable.
- An untitled section is a bare list — no head, no disclosure. Use one for the handful of items that should always be visible.
Header & footer
Code
<GdSideNav :sections="nav" product="Console" label="Console">
<template #search><SearchTrigger /></template>
<template #footer><NuxtLink to="/account" class="acct">…</NuxtLink></template>
</GdSideNav>- Turn
brandoff when a navbar above already carries the mark. A logo in both places says the brand twice and links home twice. - The search slot takes a TRIGGER, not a field. The search itself belongs in a dialog, where it has room for results.
- The footer is PINNED to the bottom by an auto top margin, so a short nav does not leave it floating in the middle of an empty column.
- Once the sections overflow, it follows them into the scroll. The auto margin resolves to zero, so it never becomes a bar covering the last destination — which is what a fixed footer does on a short screen.
- The account belongs here. Signed-in identity at the bottom of the nav is the convention, and it is the one piece of chrome with nowhere else to go once the rail has replaced the navbar.
- No popover menus in the footer. A nav is a list of destinations; hanging a menu off one of them puts a second interaction model in the same column and covers the destinations it opened from. Make the account a DESTINATION and let the account page hold the actions — the nav stays one thing, and the same row keeps working when the nav becomes a drawer, where an overlay inside an overlay is its own problem.
Rail or side nav
GdNavRail
88px, icon and a short word per destination. For a handful of TOP-LEVEL surfaces that never nest and are visited constantly — the map's tools, the workbench's modes. A rail item has to be recognisable as a picture.
GdSideNav
200–268px, words. For a catalogue: many destinations, grouped, some nested, where the NAME is the only thing that distinguishes one from the next. No icons — at this width a glyph beside every row competes with the tree it sits in.
The test is whether a destination can be drawn. "Setbacks" and "Deep planting" are both a rule page and would need the same glyph; "Map" and "Library" are different pictures. When the words are doing the work, the rail is the wrong shape and no amount of iconography rescues it.
API
GdSideNav
Props
sectionsGdNavSection[]—The whole nav, as data. A section has an optional `title` and a list of `items`; a titled section is a collapsible group, an untitled one is a bare list at the top.
productstring—The sub-brand word beside the mark — "Docs", "Console". Only drawn when `brand` is on.
labelstring—The accessible name. Two navs on a page both called "Navigation" is noise, so name them for what they hold.
widthstring--gd-size-nav (200px)A nav holding a TREE wants more than the default: a child level indents 26px and the labels have to survive it. The docs layout passes 268px.
brandbooleantrueRender the brand header. Turn it off when a navbar above the rail already carries the mark — a logo in both places says the brand twice and links home twice.
Slots
searchSits under the brand, above the first section. A trigger, not a field — the search itself belongs in a dialog.
footerPinned under the last section: a version chip, a theme toggle, a sign-out. It scrolls with the nav rather than floating over it.
GdNavSection
One group. A plain object in sections, not a component.
Props
titlestring—The head. Omit it and the section renders its items bare and always visible — top-level destinations rather than a group.
iconGdIconName—A glyph beside the title. Icons mark the TOP LEVEL and nothing under it: the ranks below are already marked by indentation, and repeating a glyph down them competes with the thing that shows depth. Give every section one or give none — a half-iconed list is a ragged left edge.
itemsGdNavItem[]—The destinations in this section.
GdNavItem
The shape of one row. Not a component — a plain object in sections[].items.
Props
labelstring—The word. No icon on an item — glyphs belong to the SECTION head; a column of them running down the tree competes with the indentation that shows depth.
tostring—Internal route. Renders a NuxtLink, and the active state comes from its own route matching — so it cannot disagree with the URL.
hrefstring—External URL.
badgenumber—A count pill on the right, same as a list row.
maturity"alpha" | "beta"—A tag on the right, for a destination that exists but is not settled.
disabledboolean—Present but not reachable. Rendered visibly inert, never hidden — a nav that hides what is coming teaches nothing.
disabledReasonstring—Why it is inert, in words. A disabled row without one is a dead end.
childrenGdNavItem[]—Makes the item a disclosure. ONE level only — a nav needing three is describing an information-architecture problem, not a component gap.
The other rail — the “On this page” contents list — is GdPageToc, documented separately because it answers a different question: this one says where you can GO, that one says where you ARE.