Skip to content
Components

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

A real GdSideNav, not a picture of one — the sections collapse, the tree opens, and the active row is whatever NuxtLink matches against the current URL. It is bounded to 440px here; in a layout it is sticky and scrolls independently of the page.
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

brand on, with a product word, a search trigger in #search, and the account in #footer — pinned to the bottom of the column, not trailing the last section. This is the arrangement an app shell uses when there is no navbar above the rail.
Code
<GdSideNav :sections="nav" product="Console" label="Console">
  <template #search><SearchTrigger /></template>
  <template #footer><NuxtLink to="/account" class="acct">…</NuxtLink></template>
</GdSideNav>
  • Turn brand off 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

PropTypeDefault
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.

brandbooleantrue

Render 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

search

Sits under the brand, above the first section. A trigger, not a field — the search itself belongs in a dialog.

footer

Pinned 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

PropTypeDefault
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

PropTypeDefault
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.

Navigate

Esc