Skip to main content
WireKit
Copy for LLM

Sticky Panel

<x-wirekit::sticky-panel> is a layout primitive for a companion column that pins itself beside an article while the page scrolls — a cart summary, a filter sidebar, a table of contents, a comparison builder. It has a non-scrolling header and footer with a scrollable body in between, and it is bounded to the viewport height so the footer never scrolls out of reach. It uses native CSS position: stickyno JavaScript.

Basic Usage

The default slot is the scrollable body; header and footer are optional non-scrolling slots. (The preview pins a short max-height so the body scrolls inside the frame.) Each line is a realistic cart row — a product-image placeholder, the name on top with its variant + quantity below, and the price kept to the right and vertically centered. Long product names truncate with an ellipsis so the row height never jumps.

Header, scrollable body, footer

In a Two-Column Layout

Place the panel beside your article in a flex row. As the article scrolls, the panel stays pinned offset from the top. Below the hideBelow breakpoint it un-sticks and flows inline (set mobile-behavior="hide" to remove it on mobile instead).

Scroll inside the frame below — the order summary stays pinned while the (taller) article moves past it. On a real page the page itself is the scroll context; here the demo pins a fixed-height scroll region so you can see the stick without leaving the docs.

Sticky summary beside a scrolling article

Review your order

Shipping address

Ada Lovelace · 12 Analytical Way · London EC1 · United Kingdom

Payment method

Visa ending 4242 · expires 09/28

Delivery

Standard (3–5 business days). Tracking emailed once your parcel leaves the warehouse.

Gift options

Add a gift message and recyclable wrap at no extra cost.

Order notes

Leave with the concierge if no one answers. Ring twice on arrival.

<div style="display: flex; gap: 2rem; align-items: flex-start;">
    <article style="flex: 1 1 auto;">
        {{-- your long-form content --}}
    </article>

    <x-wirekit::sticky-panel offset="2rem" width="20rem" label="Filters">
        <x-slot:header>
            <x-wirekit::heading :level="3" size="md">Filters</x-wirekit::heading>
        </x-slot:header>
        {{-- filter controls (scrollable) --}}
        <x-slot:footer>
            <x-wirekit::button surface="outline" class="w-full">Reset</x-wirekit::button>
        </x-slot:footer>
    </x-wirekit::sticky-panel>
</div>

position: sticky sticks relative to its nearest scrolling ancestor, not always the viewport. An ancestor with overflow: auto/scroll becomes that scroll context — the demo above relies on exactly this (the panel sticks inside the fixed-height scroll frame). The gotcha is an unintended one: if a wrapper you didn't mean to scroll sets overflow: hidden/auto/scroll, the panel silently sticks (or clips) there instead of where you expect, and overflow: hidden with no scroll room leaves it nowhere to stick. If your panel won't stick, check the ancestor chain for an unintended overflow.

Both slots are optional — omit either and the layout collapses cleanly (the body always fills the remaining height).

Body + footer, no header

Mobile sheet & collapse patterns

The panel keeps a single responsibility — a pinned, scrollable companion column. Two common "extras" are handled by composing an existing component rather than configuring this one, which keeps the markup explicit and the a11y model correct:

  • Bottom sheet on mobile — set mobileBehavior="hide" so the panel disappears below the breakpoint, then render a <x-wirekit::drawer position="bottom"> holding the same content for small screens. The drawer already provides the focus trap, backdrop, and dialog semantics a bottom sheet needs.
  • Auto-collapse a tall panel — wrap the body content in a <x-wirekit::collapsible> so the reader can fold it down when an article runs much longer than the panel. The collapsible carries its own aria-expanded button and keyboard model.

The auto-collapse pattern composes directly inside the body slot — group the panel's sections into <x-wirekit::collapsible>s so a tall companion column folds down to just the parts the reader wants:

Auto-collapse sections inside a sticky panel

Props

Prop Type Default Description
offset string '2rem' Distance from the viewport top when pinned (any CSS length). Also drives the default max-height.
maxHeight string|null null Explicit max-height override; default is calc(100dvh - 2 × offset).
width string '20rem' Panel width on desktop (capped at 100%).
hideBelow string 'md' Breakpoint (sm/md/lg/xl) at/above which the panel sticks.
mobileBehavior string 'inline' Below the breakpoint: inline (un-stick, render in flow) or hide (remove).
scrollShadow bool true Show top/bottom shadows when the body overflows. They render as overlays above the content (so a hovered row never covers them) and auto-hide at the scroll extremes. Set false to disable.
label string|null null Accessible name for the panel + its scrollable body region.
scope string|null null Scoped personalization name.

Slots

Slot Description
Default The scrollable body region
header Non-scrolling header pinned to the top of the panel
footer Non-scrolling footer pinned to the bottom of the panel

Accessibility

  • Renders as a semantic <aside> (a complementary landmark); pass label to give it an accessible name.
  • The scrollable body is a keyboard-reachable region (tabindex="0", role="region", an aria-label, and a visible focus ring) so keyboard and switch users can scroll it — WCAG 2.1.1.
  • overscroll-behavior: contain on the body stops scroll-chaining from jumping the whole page when the body reaches its scroll end.
  • Tab order follows DOM order: header → body → footer.

Keyboard Interaction

Key Action
Tab Move focus through the header, the body region, then the footer (DOM order)
Arrow keys / Page Up / Page Down Scroll the body region when it has keyboard focus

Design Tokens

Token Used for
--color-wk-bg-elevated Panel surface
--color-wk-border Panel + header/footer dividers
--radius-wk-lg Panel corner radius
--shadow-wk-md Panel elevation
--color-wk-ring Body-region focus ring
--padding-wk-x-md / --padding-wk-y-md Header / body / footer padding

Usage & Conventions

Composition. The panel is the <aside>; place it in your own two-column layout (a flex row with the article and the panel). The panel supplies the sticky behavior, the bounded height, and the scrollable body — your layout supplies the columns and the gutter.

Further Reading