Marble UI
← Components

Affix / Sticky

Preview: Default

Sticky element that knows when it's stuck (adds a shadow/border then), via a sentinel IntersectionObserver. Works inside any scroll container; `offset` is the sticky top in px.

Import

import { Affix } from '@marbleui/ui'

Props

<Affix>

PropTypeDefaultDescription
children *requiredReactNode—
classNamestring—
offsetnumber0
stuckClassNamestring'shadow-md border-border'

Usage notes

Sticky wrapper that knows when it’s stuck, for toolbars and section headers that should gain a shadow once content scrolls under them. If you don’t need the stuck styling, a plain sticky top-0 element is enough.

<Affix offset={64} className="bg-surface px-4 py-2">
  <h2 className="text-sm font-semibold">March invoices</h2>
</Affix>
  • offset is the sticky top in pixels, such as the height of a fixed header. While stuck it adds stuckClassName (default shadow-md border-border) and a data-stuck attribute.
  • It watches the nearest ancestor with overflow-y: auto or scroll, or the viewport when there is none.
  • Like any position: sticky element, it only sticks within its parent, so place it directly in the scrolling content rather than in a short wrapper.
  • It renders a 1px sentinel element before itself, which takes up a slot in flex or grid layouts with gap.
Example source · show
import { Button } from '../button'
import { Affix } from './affix'

export const styles = {
  Default: () => (
    <div className="h-80 w-96 overflow-y-auto rounded-xl border border-border bg-bg">
      <div className="p-4 text-sm text-fg-muted">Scroll down: the toolbar sticks and gains a shadow.</div>
      <Affix className="mx-2 rounded-lg bg-surface"><div className="flex items-center gap-2 p-2"><span className="text-sm font-medium text-fg">3 selected</span><Button size="sm" variant="outline" className="ml-auto">Archive</Button><Button size="sm" variant="danger">Delete</Button></div></Affix>
      <ul className="flex flex-col gap-2 p-4">{Array.from({ length: 20 }, (_, i) => <li key={i} className="rounded-lg border border-border bg-surface p-3 text-sm text-fg">Row {i + 1}</li>)}</ul>
    </div>
  ),
}

Source: packages/ui/src/affix/affix.tsx

Catalog

Category
utilities
Priority
Extra
Primitive
custom