Skip to content

Commit 7ca50be

Browse files
authored
Merge pull request #18 from surjithctly/sticky-header
feat: add sticky header utility
2 parents 9760684 + 5acf7e3 commit 7ca50be

File tree

4 files changed

+93
-2
lines changed

4 files changed

+93
-2
lines changed

README.md

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
Astro-Navbar is a fully responsive and accessible headless navigation bar for Astro, supporting nested dropdowns and mobile-responsive toggles.
44

55
### Live Demos
6+
67
- [**Stackblitz**](https://stackblitz.com/edit/github-jpfnv9?file=src/pages/index.astro)
78
- [**Astroship Template**](https://astroship.web3templates.com/)
89

@@ -23,6 +24,7 @@ Ensure you have the `.hidden` class in your CSS. If not, add the following:
2324
display: none;
2425
}
2526
```
27+
2628
Then integrate the navigation bar:
2729

2830
```astro
@@ -73,6 +75,7 @@ import { Astronav, MenuItems, MenuIcon, Dropdown, DropdownItems, DropdownSubmenu
7375
</Astronav>
7476
</div>
7577
```
78+
7679
## Customization
7780

7881
### Styling
@@ -127,7 +130,7 @@ import { Astronav, MenuIcon, OpenIcon, CloseIcon } from "astro-navbar";
127130

128131
## Using with Tailwind CSS
129132

130-
Astro-Navbar pairs well with Tailwind CSS.
133+
Astro-Navbar pairs well with Tailwind CSS.
131134

132135
<details>
133136
<summary>Minimal Usage Example with Tailwind CSS</summary>
@@ -185,6 +188,35 @@ import { Astronav, MenuItems, MenuIcon, Dropdown, DropdownItems } from "astro-n
185188

186189
</details>
187190

191+
## Utilities
192+
193+
Some related utilities are provided for convenience.
194+
195+
### Sticky Header
196+
197+
To make the header sticky, you can use the `<StickyHeader />` component. This will help you to add custom classes to the header when scrolled such as `sticky`. Since this is a headless component, no sticky classes has been added by default. You can add your own classes. This utility adds a tiny JS snippet to detect scroll position in a performant way.
198+
199+
Here's an example:
200+
201+
```js
202+
// Wrap the header with sticky header (renders as <header>...</header>)
203+
204+
<StickyHeader
205+
// default class. applied all the time. No changes
206+
class="sticky top-0 border-b z-20 transition-all"
207+
// scroll threshold to enable active class
208+
scrollY={50}
209+
// initial classes which will be removed when scrollY reached
210+
defaultClass="py-5 border-transparent"
211+
// active classes to add when scrollY reached.
212+
// "is-active" class will be added by default
213+
activeClass="py-2 bg-white/80 border-gray-200 backdrop-blur-lg">
214+
// ...
215+
<Astronav>...</Astronav>
216+
// ...
217+
</StickyHeader>
218+
```
219+
188220
## Options
189221

190222
Here are the supported options / props for this plugin.

index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ export { default as MenuItems } from "./src/components/MenuItems.astro";
66
export { default as Dropdown } from "./src/components/Dropdown.astro";
77
export { default as DropdownSubmenu } from "./src/components/DropdownSubmenu.astro";
88
export { default as DropdownItems } from "./src/components/DropdownItems.astro";
9+
export { default as StickyHeader } from "./src/components/StickyHeader.astro";

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "astro-navbar",
3-
"version": "2.2.1",
3+
"version": "2.3.0",
44
"description": "Responsive Mobile Navigation with Dropdown in Astro",
55
"type": "module",
66
"exports": "./index.ts",

src/components/StickyHeader.astro

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
---
2+
interface Props {
3+
scrollY?: number;
4+
activeClass?: string;
5+
defaultClass?: string;
6+
class?: string;
7+
}
8+
const {
9+
scrollY = 100,
10+
defaultClass = "",
11+
activeClass = "",
12+
class: className = "",
13+
} = Astro.props;
14+
---
15+
16+
<header class:list={["astronav-sticky-header", className, defaultClass]}>
17+
<slot />
18+
</header>
19+
20+
<script define:vars={{ scrollY, defaultClass, activeClass }}>
21+
let scrollPos = 0;
22+
let ticking = false;
23+
24+
function OnScroll(scrollPos) {
25+
const headers = document.querySelectorAll(".astronav-sticky-header");
26+
const classArray = activeClass.split(" ");
27+
const replaceArray = defaultClass.split(" ");
28+
29+
headers.forEach((header) => {
30+
if (scrollPos > scrollY) {
31+
header.classList.remove(...replaceArray);
32+
header.classList.add("is-active", ...classArray);
33+
header.setAttribute("active", "");
34+
}
35+
//reduce the scrollY to avoid flickering when scrolling up
36+
if (scrollPos < Math.max(scrollY - 20, 0)) {
37+
header.classList.remove("is-active", ...classArray);
38+
header.classList.add(...replaceArray);
39+
header.removeAttribute("active");
40+
}
41+
});
42+
}
43+
44+
// Scroll event throttling as per MDN
45+
// https://developer.mozilla.org/en-US/docs/Web/API/Document/scroll_event
46+
47+
document.addEventListener("scroll", (event) => {
48+
scrollPos = window.scrollY;
49+
if (!ticking) {
50+
window.requestAnimationFrame(() => {
51+
OnScroll(scrollPos);
52+
ticking = false;
53+
});
54+
55+
ticking = true;
56+
}
57+
});
58+
</script>

0 commit comments

Comments
 (0)