Skip to content
Protocore Design Systemv1.6.9

/// Utilities

Affix

Pins its children to the viewport with fixed positioning in a portal, with an optional scroll threshold to reveal it.

import { Affix } from "@protocore/pds";
View as Markdown

Basics

Affix renders its children position: fixed relative to the viewport, in a portal at the document root. Set position with viewport offsets — left/right resolve to logical insets, so it mirrors correctly under RTL.

Toggle a viewport-pinned notice. It renders fixed to the bottom-end corner of the window, in a portal, above page content.

Back to top

Pass scrollThreshold to reveal the affix only after the page has scrolled a given distance — the classic back-to-top button. Below the threshold it renders nothing.

Scroll the page down: once you pass 300px the back-to-top control fades in, pinned to the bottom-end corner of the viewport. It portals out of this demo frame.

When to use it

Use Affix for viewport-anchored UI that must float above the page and survive scrolling — a back-to-top button, a floating action button, a persistent cookie or status notice. It portals to the document root so it escapes any overflow or transform ancestor that would otherwise clip a fixed element, and sits at the sticky z-index. The optional scrollThreshold reveals it only once the reader has scrolled past a point. For content that should scroll *with* a column but stick within it, use native position: sticky instead — Affix is specifically for viewport-fixed elements.

Usage

Do

  • Use Affix for viewport-fixed floating UI (back-to-top, FAB, persistent notice).
  • Set a scrollThreshold for reveal-on-scroll affordances so they don't clutter the top of the page.
  • Give the affixed control a clear aria-label — it's detached from surrounding context.

Don't

  • Use Affix for content that should stick within a scrolling column — that's position: sticky.
  • Stack many affixes at the same corner; they'll overlap and trap focus.
  • Assume left/right are physical — they are logical insets and flip under RTL.

Accessibility

  • Affix is a portaled container; the interactive control inside it must be a real button/link with its own accessible name.
  • Because it is visually detached, give affixed controls an explicit label (e.g. aria-label="Back to top").
  • Its appearance fades in with a short animation that honors prefers-reduced-motion.

Affix props

PropTypeDefaultDescription
classNamestring
positionAffixPosition{ bottom: 20, right: 20 }Viewport offsets.
scrollThresholdnumberOnly show the affix once the window has scrolled at least this many pixels vertically. Omit to always show it.
styleCSSProperties
targetHTMLElement | nulldocument.bodyPortal target.
zIndexstring | numbervar(--pds-z-sticky)Override the stacking order.

Related

  • ScrollAreaA scrollable viewport with thin, sharp, hairline scrollbars — on either or both axes, with configurable visibility.
  • PdsProviderStamps theme/accent/density/env on a subtree and exposes them via context.