Styles live in scss/components/_anchor-nav.scss. In-page anchor navigation links sections on long pages with a vertical rail and optional icons.
Anatomy
| Part | Class | Role |
|---|---|---|
| Nav | .anchor-nav | Vertical <nav>; width fits longest label |
| Constrained | .anchor-nav--constrained | Optional fixed ~110px column with ellipsis |
| Item | .anchor-item | Section link with left border rail |
| Level 2 | .anchor-item--level-2 | Indented child section (+8px margin) |
| Selected | .anchor-item--selected | Active section; pair with aria-current |
| Icon | .anchor-item__icon | Optional 20px icons (level 1 only) |
| Label | .anchor-item__label | Text slot; hover surface wraps item (8px padding) |
Prerequisites
- PimentCSS installed, Installation.
- Icons (optional),
link-01at 20px viaph(). - Section IDs, each
hrefshould target a heading or regionidon the page.
Anchor items, level 1
By default, .anchor-nav and each .anchor-item grow to the full label width (plus 8px padding); labels are never truncated. Hover and doc-only .anchor-item--hover wrap that box. For a narrow sidebar with ellipsis, add .anchor-nav--constrained. Icons are optional via .anchor-item__icon. Doc-only .anchor-item--focus previews the focus ring; production uses :focus-visible. Selected uses aria-current="true".
Anchor items, level 2
Child sections use .anchor-item--level-2 (extra 8px left margin so hover aligns with indented text) and aria-current="page" when that section is active.
Vertical anchor block
Stack links inside .anchor-nav. Mix level 1 and level 2 items; only one section should be current at a time.
<nav class="anchor-nav" aria-label="Sections"><a href="#intro" class="anchor-item anchor-item--selected" aria-current="true">
<span class="anchor-item__label">Introduction</span>
</a><a href="#details" class="anchor-item anchor-item--level-2">
<span class="anchor-item__label">Details</span>
</a></nav>
Interactive example
Add data-anchor-live on .anchor-nav and call wireAllAnchorNavs() after load. Clicks update aria-current (demo prevents navigation). In production, pair with scroll-spy or native hash navigation.
// See docs-site/src/lib/anchor-behavior.ts (aria-current on section click).
Class reference
| Class | Description |
|---|---|
.anchor-nav | Vertical nav; width fits content |
.anchor-nav--constrained | Optional max ~110px + ellipsis |
.anchor-item | Section link (fit-content width, min-height 44px, hover on padded box) |
.anchor-item--level-2 | Indented subsection (+8px margin-inline-start) |
.anchor-item--selected | Active link (2px left border, semi-bold) |
.anchor-item--hover | Doc-only hover preview |
.anchor-item--focus | Doc-only focus ring preview |
.anchor-item__icon | 20px optional icon |
.anchor-item__label | Label text |
Customize (Sass)
-
Anchor spacing
Override gaps, padding, and selected border width.@use "pimentcss-design-system" with ( $anchor-item-gap: 0.75rem, $anchor-item-py: 0.5rem, $anchor-item-px-l1: 0.5rem, $anchor-item-px-l2: 1rem, $anchor-border-selected: 0.125rem ); -
Rebuild CSS
Run after editing _anchor-nav.scss.npm run build:css
Accessibility (RGAA / WCAG)
In-page navigation
- Landmark, use
<nav aria-label="Sections">for the anchor list. - Current section, set
aria-current="true"on level 1 oraria-current="page"on level 2 (with.anchor-item--selected). - Targets, each
hrefmust match a visible sectionid; avoid empty#in production. - Focus, visible
:focus-visibleoutline on links. - Touch, items are at least 44px tall by default.
- Skip link, consider a skip link before the anchor nav on long pages.