Skip to main content
PimentCSS v1.0.1, what's new
Home

In-page anchors

In-page anchor list with scroll-spy style active states.

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

PartClassRole
Nav.anchor-navVertical <nav>; width fits longest label
Constrained.anchor-nav--constrainedOptional fixed ~110px column with ellipsis
Item.anchor-itemSection link with left border rail
Level 2.anchor-item--level-2Indented child section (+8px margin)
Selected.anchor-item--selectedActive section; pair with aria-current
Icon.anchor-item__iconOptional 20px icons (level 1 only)
Label.anchor-item__labelText slot; hover surface wraps item (8px padding)

Prerequisites

  • PimentCSS installed, Installation.
  • Icons (optional), link-01 at 20px via ph().
  • Section IDs, each href should target a heading or region id on 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".

Default
Focus
Hover
Unselected
Anchor item
Anchor item
Anchor item
Selected
Anchor item
Anchor item
Anchor item

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.

Default
Focus
Hover
Unselected
Anchor item
Anchor item
Anchor item
Selected
Anchor item
Anchor item
Anchor item

Vertical anchor block

Stack links inside .anchor-nav. Mix level 1 and level 2 items; only one section should be current at a time.

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.

Class reference

ClassDescription
.anchor-navVertical nav; width fits content
.anchor-nav--constrainedOptional max ~110px + ellipsis
.anchor-itemSection link (fit-content width, min-height 44px, hover on padded box)
.anchor-item--level-2Indented subsection (+8px margin-inline-start)
.anchor-item--selectedActive link (2px left border, semi-bold)
.anchor-item--hoverDoc-only hover preview
.anchor-item--focusDoc-only focus ring preview
.anchor-item__icon20px optional icon
.anchor-item__labelLabel text

Customize (Sass)

  1. 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
    );
  2. 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 or aria-current="page" on level 2 (with .anchor-item--selected).
  • Targets, each href must match a visible section id; avoid empty # in production.
  • Focus, visible :focus-visible outline on links.
  • Touch, items are at least 44px tall by default.
  • Skip link, consider a skip link before the anchor nav on long pages.

Next steps