Sticky headers
Use the koala-sticky-header tag helper
to create a header bar that appears when the user scrolls past the original page header. It slides in from the top with a smooth
transition and stays fixed until the user scrolls back up. Used on detail pages (view quote, view partner, view transaction, etc.)
to keep key information and actions accessible.
How it works
The tag helper renders a zero-height sentinel element and a fixed header bar. An IntersectionObserver
watches the sentinel — when it scrolls out of the viewport, the sticky header slides in. The parent element must have
x-data with an
isSticky property and an
init() method that sets up the observer.
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
koala-sticky-header |
marker | - | Activates the sticky header tag helper on a <div> |
koala-sticky-header-max-width |
string |
max-w-screen-2xl |
Tailwind max-width class for the inner container |
Required Alpine.js setup
The parent element must include x-data with
isSticky: false and an
init() that creates an IntersectionObserver.
The rootMargin: '-64px 0px 0px 0px' accounts
for the fixed navbar height. In the Portal, the style also includes
sidebarCollapsed awareness for the sidebar margin.
<div x-data="{
isSticky: false,
init() {
const observer = new IntersectionObserver(
([entry]) => { this.isSticky = !entry.isIntersecting },
{ rootMargin: '-64px 0px 0px 0px' }
);
observer.observe(this.$refs.sentinel);
}
}">
<div koala-sticky-header>
<!-- Sticky header content (title, badges, action buttons) -->
</div>
<!-- Page content below -->
</div>
Rendered output
The tag helper replaces the <div koala-sticky-header>
with a zero-height sentinel and a fixed bar. The bar uses
x-show="isSticky" with enter/leave transitions.
<div x-ref="sentinel" class="h-0"></div>
<div x-show="isSticky"
x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="-translate-y-full opacity-0"
x-transition:enter-end="translate-y-0 opacity-100"
x-transition:leave="transition ease-in duration-150"
x-transition:leave-start="translate-y-0 opacity-100"
x-transition:leave-end="-translate-y-full opacity-0"
x-cloak
class="fixed left-0 right-0 z-20 bg-white dark:bg-gray-800
border-b border-gray-200 dark:border-gray-700"
style="top: calc(4rem + var(--env-banner-h, 0px));"
x-bind:class="sidebarCollapsed ? 'lg:ml-16' : 'lg:ml-64'">
<div class="max-w-screen-2xl mx-auto px-4 sm:px-6 py-3
flex items-center justify-between gap-3">
<!-- Child content -->
</div>
</div>
Live demo
Scroll down within the bordered box below. When the page header scrolls out of view, a sticky header appears at the top of the container.
KQ-20260331-001 v1
NewQuote KQ-20260331-001
Created 31 March 2026
Property details
- Address
- 42 Koala Lane, London, SW1A 1AA
- Price
- £450,000
- Type
- Sale - Freehold
- Property
- House
Fee breakdown
- Legal fee
- £850.00
- Search pack
- £320.00
- Land Registry
- £100.00
- Total
- £1,270.00
Client details
- Name
- Jane Smith
- jane.smith@example.com
- Phone
- 07700 900123
Usage in a detail page
A typical detail page places the sticky header immediately after the breadcrumbs. The child content usually includes a title, status badge, and action buttons.
<div class="mb-6" x-data="{
isSticky: false,
init() {
const observer = new IntersectionObserver(
([entry]) => { this.isSticky = !entry.isIntersecting },
{ rootMargin: '-64px 0px 0px 0px' }
);
observer.observe(this.$refs.sentinel);
}
}">
<div koala-sticky-header>
<div class="flex items-center gap-3 min-w-0">
<h2 class="text-lg font-semibold font-mono text-gray-900
dark:text-white truncate">
@Model.Quote.Reference v@(Model.Quote.Version)
</h2>
<span koala-badge="Neutral" koala-badge-size="Small">New</span>
</div>
<div class="hidden sm:flex items-center gap-2">
<button type="button" koala-btn="Primary">Accept</button>
</div>
</div>
<!-- Original page header -->
<h1 class="text-2xl font-bold ...">Quote @Model.Quote.Reference</h1>
<!-- Page content -->
</div>
Custom max-width
Override the inner container's max-width with koala-sticky-header-max-width.
The default is max-w-screen-2xl.
<div koala-sticky-header koala-sticky-header-max-width="max-w-4xl">
<!-- Content constrained to max-w-4xl -->
</div>