A lightweight Alpine.js directive that toggles CSS classes based on scroll position, it handles pinned, unpinned, top, bottom, frozen states with custom options for offset and tolerance
npm install @designbycode/alpine-headroomfrozen modifier for static state
bash
npm install @designbycode/alpine-headroom
or
bun add @designbycode/alpine-headroom
`
> Ensure you use Tailwind CSS v4 only in your build config
Usage
Import and register the plugin in your entry point (eg main.js):
`js
import Alpine from "alpinejs"
import Headroom from "@designbycode/alpine-headroom"
Alpine.plugin(Headroom)
Alpine.start()
`
$3
Add the x-headroom directive to any element:
`html
`
* offset (number) minimum scroll Y before toggling pinned/unpinned
* tolerance (number) scroll delta threshold to ignore small moves
* classes (object) override default Tailwind CSS v4 class names
`css
.headroom {
will-change: transform; / Optimize for animation /
transition: transform 0.5s ease-in-out; / Smooth transition /
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
}
/ Styles when the element is pinned (visible) /
.headroom--pinned {
transform: translateY(0%);
}
/ Styles when the element is unpinned (hidden) /
.headroom--unpinned {
transform: translateY(-100%); / Slide up and out of view /
}
/ Optional: Styles for when the page is at the very top /
.headroom--top {
/ Example: Add a shadow only when not at the top /
box-shadow: none;
}
.headroom--not-top {
box-shadow: 0 3px rgba(0,0,0,25);
}
`
Use modifiers in the directive to apply frozen state at init:
`html
`
Options
Default options are:
`js
{
offset: 0,
tolerance: 0,
classes: {
initial: "headroom",
pinned: "headroom--pinned",
unpinned: "headroom--unpinned",
top: "headroom--top",
notTop: "headroom--not-top",
bottom: "headroom--bottom",
notBottom: "headroom--not-bottom",
frozen: "headroom--frozen"
}
}
`
Override any of these by passing an object to x-headroom="..." expression, customising only what you need, classes supports multiple Tailwind utility classes separated by spaces
Code Example
`ts
// headroom.ts
import Alpine from "alpinejs"
import Headroom from "@designbycode/alpine-headroom"
Alpine.plugin(Headroom)
Alpine.start()
`
`html
Alpine Headroom Demo
My Site
Scroll down to see header hide, scroll up to show
``