Skip to main content
Urbicon UI

Sticky Pinning

Pin the toolbar, column header, and group header to the top of the scroll ancestor on long lists. Keeps context visible while scrolling through hundreds of rows.

The sticky prop pins one or more of the table's three contextual layers — toolbar (L1), column header (L2), and group header (L3 when grouping is active). The pin position is offset by the height of each preceding layer using CSS custom properties, so the layers stack naturally below your app shell's top bar.

For tables wider than the viewport, reach for fit="viewport" (see below) — it contains both axes of scroll inside the table, so the page never scrolls sideways.

sticky
stickyOffset: 0px

Scroll the page to see the pinned layer(s). Adjust stickyOffset to simulate a fixed app-shell top bar.

No data available

No data available

sticky (defaults to both)

Pin toolbar + header + group header. The visual stack mirrors the DOM order.

No data available

No data available
Loading...
Loading syntax highlighting...

Toolbar only

Pin only the toolbar; the column header scrolls with the rest of the table.

No data available

No data available
Loading...
Loading syntax highlighting...

Header only

Pin only the column header (plus group header when grouping is active). The toolbar scrolls with the page.

No data available

No data available
Loading...
Loading syntax highlighting...

With stickyOffset for app-shell top bar

If your layout has a fixed top bar, pass its height in pixels so the pin lands just below it.

No data available

No data available
Loading...
Loading syntax highlighting...

The default toolbar is the SmartFilterBar. Override it with the toolbar snippet — the custom content inherits the same sticky wrapper.

Custom toolbar snippet

Replace SmartFilterBar entirely while keeping the sticky behavior.
Loading...
Loading syntax highlighting...

Contained scroll — fit="viewport"

Page-relative sticky pinning and in-table horizontal scroll are mutually exclusive: a single element cannot be both a sticky-pin host and a scroll ancestor. So with sticky="header", a table wider than the viewport pushes its horizontal overflow onto the page — the whole layout scrolls sideways.

fit="viewport" resolves this by making the table its own scroll container. It is height-capped to the viewport (measured automatically — no magic max-height), the column and group headers pin to the top of the box, and the toolbar + pagination stay fixed outside the scrolling area. Only the rows scroll, horizontally and vertically.

Full-height list page

The table fills the available viewport height. Header pinned, toolbar + pagination fixed, rows scroll in both directions. Supersedes the sticky prop; desktop-only (mobile keeps document scroll).
Loading...
Loading syntax highlighting...

fit="viewport" supersedes sticky and stickyOffset (the measured top absorbs app-shell offsets). It is mutually exclusive with virtualized, which keeps its own virtualHeight scroll box.

Caveats

  • Sticky pinning anchors to the nearest scrollable ancestor. If you wrap the table in a container with overflow: auto/hidden, the pin will bind to that container — usually what you want inside a Drawer body, less so inside an unintentional overflow wrapper.
  • Enabling sticky="header" or "both" disables the table's internal horizontal scrolling (the scroll area can't be both a sticky pin host AND a scroll ancestor at the same time). Very wide tables fall back to page-level horizontal scrolling — switch to fit="viewport" to contain it instead.
  • unstyled mode strips the sticky classes — pinning is a layout function, not pure styling. Apply your own via slotClasses.toolbar / slotClasses.thead when running unstyled.