Package Exports
- @sofidevo/astro-dynamic-header
- @sofidevo/astro-dynamic-header/HamburgerButton
- @sofidevo/astro-dynamic-header/HamburgerButton.astro
- @sofidevo/astro-dynamic-header/Header
- @sofidevo/astro-dynamic-header/Header.astro
- @sofidevo/astro-dynamic-header/MobileNav
- @sofidevo/astro-dynamic-header/MobileNav.astro
- @sofidevo/astro-dynamic-header/NavMenu
- @sofidevo/astro-dynamic-header/NavMenu.astro
Readme
@sofidevo/astro-dynamic-header
A dynamic, responsive header component for Astro projects that can switch between floating and fullscreen styles with multi-level dropdown navigation support.
[!WARNING] Breaking Changes — v2.2+: The
logoprop has been removed in favor of a much more flexiblelogoslot. Thecolorprop has also been removed from theHamburgerButtoncomponent to ensure flawless dark mode synchronization. Thethemeproperty behavior was also refactored to prioritize native CSS variables, reducing DOM bloat and enabling purely CSS-based customization. See the Changelog section below.
[!WARNING] Breaking Changes — v2.0+: The
logoandnavigationprops were restructured from strings/arrays to configuration objects. See the Component Props and Comprehensive Example to migrate.
[!NOTE] What's new — v2.1:
CustomClassNameshas been renamedHeaderClassNames(the old name still works as an alias). New nested class props added toLogoConfigandNavConfig. NewmobileNavslot inHeaderClassNames.defaultThemesis now exported for use outside the component. See the Changelog section below.
Features
- Dynamic Styles: Switch between floating and fullscreen header layouts
- Fully Responsive: Mobile-first design with hamburger menu
- Multi-level Dropdowns: Support for nested navigation menus
- Slot Support: Customizable slots for desktop header and mobile panel content
- TypeScript Support: Full type safety and IntelliSense
- Two-layer customization: High-level
classNamesprop + fine-grained nested class props insidenavigationandlogo - Exportable defaults: Import and extend
defaultThemesfrom your own code - Astro Optimized: Built specifically for Astro framework
Live demo
https://base-astro-psi.vercel.app/fullscreen-demo
Installation
npm i @sofidevo/astro-dynamic-headerRequired Dependencies
You need to add the Iconify CDN to the head of your project for the hamburger menu icons to work properly:
<script src="https://code.iconify.design/iconify-icon/3.0.0/iconify-icon.min.js"></script>Add this to your main layout or in the <head> section of your Astro pages.
Quick Start
Basic Usage (Automatic Theme)
By default, the header uses preset="auto", which automatically detects the theme based on a .dark class on your root element (html or body).
---
import Header from '@sofidevo/astro-dynamic-header/Header';
const menuItems = [
{ link: '/about', text: 'About' },
];
---
<!-- Detects .dark class on root automatically -->
<Header navigation={{ menuItems }} />Advanced Usage (Dual-Theme Customization)
You can provide custom colors for both light and dark modes simultaneously.
---
import Header from '@sofidevo/astro-dynamic-header/Header';
const navigation = {
menuItems: [
{ link: '/about', text: 'About' },
]
};
const theme = {
light: {
accentColor: "#3e1c71",
backgroundColor: "rgba(255, 255, 255, 0.8)"
},
dark: {
accentColor: "#00ffff",
backgroundColor: "rgba(20, 20, 20, 0.9)"
}
};
---
<Header
preset="auto"
theme={theme}
navigation={navigation}
/>Component Props
Header Component
| Prop | Type | Default | Description |
|---|---|---|---|
headerType |
"floating" | "fullscreen" |
"floating" |
Header layout style |
preset |
"light" | "dark" | "auto" |
"auto" |
Theme behavior. auto follows root class. |
navigation |
NavConfig |
{} |
Navigation configuration object |
theme |
DualThemeConfig |
{} |
Custom theme overrides for light/dark |
classNames |
HeaderClassNames |
{} |
High-level class overrides for layout elements |
Config Objects
DualThemeConfig
| Propery | Type | Description |
|---|---|---|
light |
ThemeConfig |
Styles applied in light mode |
dark |
ThemeConfig |
Styles applied in dark mode |
ThemeConfig
| Propery | Type | Default |
|---|---|---|
backgroundColor |
string |
Preset default |
backgroundColorOpaque |
string |
Preset default |
backdropBlur |
string |
"blur(20px)" |
zIndex |
number |
10 |
textColor |
string |
Preset default |
accentColor |
string |
Preset default |
[!IMPORTANT] Transparency vs Solid Submenus: To ensure the best UI and avoid rendering bugs with
backdrop-filteron nested elements, submenus and the mobile navigation panel are solid/opaque.If you use a transparent
backgroundColor(e.g.,rgba), remember to also provide its solid counterpart inbackgroundColorOpaque.
<Header theme={{
light: {
backgroundColor: "rgba(255, 255, 255, 0.7)", // Transparent header body
backgroundColorOpaque: "#ffffff", // Solid submenus
}
}} />CustomClassNames → HeaderClassNames
[!NOTE]
CustomClassNameswas renamed toHeaderClassNamesin v2.1. The old name still works as a type alias — no migration required.
The classNames prop targets the structural wrapper elements of the Header. For fine-grained control of individual nav links or the logo internals, use the nested xxx__class props inside the navigation or logo config objects instead.
| Property | Target Element | Purpose & Common Use Cases |
|---|---|---|
container |
Outer div wrapping the header |
Positioning & Layout: top-0, z-50, fixed, adjusting max-width and mx-auto logic. |
header |
Inner <header> element |
Appearance: Shadows (shadow-md), borders (border-b), or custom transition durations. |
logo |
<a> tag surrounding the logo |
Interactions: Hover states, custom focus rings, or adjusting the flex alignment of the logo group. |
logoText |
<span> tag containing the logo text |
Typography: Font weights, text shadows, or specific tracking/leading classes. |
nav |
<div> wrapping the desktop navigation items |
Desktop Layout: Spacing between the logo and the menu, or responsive visibility classes (hidden md:flex). |
mobileNav |
Root <nav> of the mobile slide-in panel |
Mobile Panel: Extra backdrop blur, custom z-index, slide-in overrides. |
Usage Examples
Premium Shadow & Border:
<Header
classNames={{
header: "shadow-xl border-b border-black/5 dark:border-white/10 transition-all duration-500",
container: "top-4 px-6",
mobileNav: "backdrop-blur-md",
}}
/>Custom Typography & Nav Spacing:
<Header
classNames={{
logoText: "tracking-tighter font-black italic uppercase",
nav: "ml-auto gap-8",
}}
/>[!TIP] Since these classes are injected using Astro's
class:list, you can also pass objects or arrays if you need conditional logic for your custom classes.
NavConfig
| Property | Type | Description |
|---|---|---|
homeUrl |
string |
URL for the home link (defaults to /) |
menuItems |
MenuItem[] |
Array of navigation menu items |
header__menu__class |
string |
Extra CSS class(es) for the desktop <nav> element |
header__item__class |
string |
Extra CSS class(es) for each top-level <li> menu item |
menu__link__class |
string |
Extra CSS class(es) for each top-level <a> link |
MenuItem
| Property | Type | Description |
|---|---|---|
link |
string |
URL the menu item points to |
text |
string |
Label text for the menu item |
submenu |
SecondaryMenuItem[] |
Optional array of nested menu items |
Slots Support
The Header component provides a flexible slot system that allows you to add additional content:
Available Slots
| Slot Name | Location | Visibility | Description |
|---|---|---|---|
logo |
Header Desktop/Mobile | Always | Add your custom logo HTML/Components |
actions |
Header & Mobile panel | Responsive visibility | Add action buttons (login, signup, etc.) |
Example with Slots
---
import Header from '@sofidevo/astro-dynamic-header/Header';
const navigation = {
menuItems: [{ link: '/about', text: 'About' }]
};
---
<Header navigation={navigation}>
<div slot="actions">
<button class="login-btn">Login</button>
</div>
</Header>Comprehensive Example
Below is a complete implementation example showcasing custom logo configuration, navigation with a home URL, and theme overrides.
---
import Header from '@sofidevo/astro-dynamic-header/Header';
const menuItems = [
{
link: "#",
text: "Services",
submenu: [
{ link: "/design", text: "Design" },
{ link: "/consulting", text: "Consulting" },
{
link: "#",
text: "Web Development",
submenu: [
{ link: "/web/frontend", text: "Frontend" },
{ link: "/web/backend", text: "Backend" },
{ link: "/web/fullstack", text: "Full Stack" },
],
},
],
},
{ link: "/about", text: "About" },
{ link: "/contact", text: "Contact" },
];
];
---
<style is:inline>
:root {
/* Pure CSS Theming Configuration */
--l-accent: #ff0000;
--l-bg: rgba(255, 255, 255, 0.8);
--d-accent: #00ffff;
--d-bg: rgba(20, 20, 20, 0.9);
}
</style>
<Header
headerType="floating"
preset="dark"
navigation={{
homeUrl: "/",
menuItems: menuItems,
header__menu__class: "flex gap-6",
menu__link__class: "font-medium",
}}
classNames={{
header: "shadow-xl",
mobileNav: "backdrop-blur-md",
}}
>
<a slot="logo" href="/" style="display: flex; align-items: center; gap: 10px; color: inherit; text-decoration: none;">
<img src="https://sofidev.blog/img/branding/logo.webp" alt="My Site Logo" width="44" />
<span style="font-weight: bold; font-size: 1.2rem;">SofiDev</span>
</a>
<button slot="actions">Login</button>
</Header>Header Types
Floating Header
- Centered with max-width constraint
- Rounded corners
- Padding around container
- Perfect for modern, card-like designs
Fullscreen Header
- Full viewport width
- No border radius
- Edge-to-edge design
- Ideal for traditional website layouts
Styling and Customization
The component uses CSS custom properties that you can override:
:root {
--light-spot-color: #00ffff;
--color-tertiary: #ffffff;
--color-hamburger-lines: #ffffff;
}TypeScript Support
The package provides full TypeScript support. You can import types to ensure your configuration is correct:
---
import Header from '@sofidevo/astro-dynamic-header/Header';
import { defaultThemes } from '@sofidevo/astro-dynamic-header';
import type {
NavConfig,
DualThemeConfig,
HeaderClassNames,
MenuItem,
SecondaryMenuItem
} from '@sofidevo/astro-dynamic-header';
const navigation: NavConfig = {
menuItems: [
{
link: '/products',
text: 'Products',
submenu: [
{ link: '/software', text: 'Software' },
{ link: '/hardware', text: 'Hardware' }
]
}
],
header__menu__class: "flex gap-6",
};
// Prefer CSS custom properties globally rather than passing the `theme` object.
// But you can still use the theme prop if needed:
const theme: DualThemeConfig = {
light: { ...defaultThemes.light, accentColor: "#3e1c71" },
dark: { ...defaultThemes.dark, accentColor: "#00ffff", backgroundColor: "rgba(10, 10, 10, 0.9)" },
};
const classNames: HeaderClassNames = {
header: "shadow-xl",
mobileNav: "backdrop-blur-md",
};
---
<Header
navigation={navigation}
classNames={classNames}
preset="auto"
/>Available Types
| Type | Description |
|---|---|
MenuItem |
Top-level menu item with optional properties |
SecondaryMenuItem |
Second-level menu item |
TertiaryMenuItem |
Third-level menu item |
NavConfig |
Navigation config (items + nested class props) |
ThemeConfig |
Individual theme settings (colors, blur, etc.) |
DualThemeConfig |
Combined settings for light and dark modes |
HeaderClassNames |
Class overrides for structural wrapper elements |
CustomClassNames |
Deprecated alias for HeaderClassNames |
HeaderProps |
Main props for the Header component |
Browser Support
- All modern browsers (Chrome, Firefox, Safari, Edge)
- Mobile responsive design with optimized touch targets
- Supports CSS
backdrop-filterfor glassmorphism - Automatic theme switching based on OS or site preference via
.darkclass
Troubleshooting
Import Issues
If you encounter import errors, try these solutions:
Use direct subpath import:
import Header from '@sofidevo/astro-dynamic-header/Header';Check relative imports in TS: In some environments (like
node16), you might need to use the.jsextension even for TypeScript files when importing from the package internals, though the main entry point handles this for you.Verify TypeScript configuration:
// tsconfig.json { "compilerOptions": { "moduleResolution": "bundler", "allowImportingTsExtensions": true } }
Compatibility
- Astro 4.x and 5.x
- SSG Projects (Static Site Generation)
- SSR Projects (Server-Side Rendering)
- Hybrid Projects (output: 'hybrid')
Live Examples
Visit our demo website to see the component in action with interactive examples and complete documentation.
License
MIT License - see the LICENSE file for details.
Support
If you find this package helpful, please consider giving it a star on GitHub!
Changelog
v2.2 — Performance & DX Optimization
Breaking changes
- Removed
logoObject Configuration prop: Thelogoproperty andLogoConfiginterface have been removed. You should now use<slot name="logo" />to render your logo exactly as you need, passing native HTML or Astro components. - Removed
colorprop fromHamburgerButton: TheHamburgerButtonnow inherits--text-colornatively via CSS, which fixes a bug where the button would not properly update its color when switching to dark mode. Any direct uses of<HamburgerButton color="..." />will fail to compile in TypeScript and should be updated to rely on global CSS variables or context inheritance.
New features and enhancements
- Native CSS Variable Theming (Better DX): Redesigned how default styles are injected into the DOM.
Header.astrono longer injects all default properties intostyle={...}attributes on load, solving the "DOM bloat" issue. You can now deeply customize the component purely by setting CSS variables like--l-bg,--d-bg,--l-accent, and--d-accentinside your:rootstyle tag, removing the necessity to parse massivethemeJS objects. - Dead Code Elimination: Cleaned up repetitive prop destructuring inside
MobileNav.astro.
v2.1 — Style & Customization Refactor
New features
HeaderClassNamesreplacesCustomClassNames(alias kept — no migration required). NewmobileNavslot targets the mobile slide-in<nav>panel.Nested class props on
LogoConfig:Prop Targets logo__container__classLogo <a>wrapperlogo__text__classLogo text <span>Nested class props on
NavConfig:Prop Targets header__menu__classDesktop <nav>elementheader__item__classEach top-level <li>menu__link__classEach top-level <a>defaultThemesexported — import and spread the built-in tokens to extend them:import { defaultThemes } from "@sofidevo/astro-dynamic-header"; const theme = { dark: { ...defaultThemes.dark, accentColor: "#f43f5e" } };
Internal improvements
- Default theme tokens extracted to
src/defaults.ts— easier to read and maintain. HamburgerButtoncolor is now explicitly wired from the resolved theme (no visual change).
Deprecations
CustomClassNames— useHeaderClassNamesinstead. The alias will remain until the next major version.
v2.0 — Object-based Configuration API
[!WARNING] Breaking change:
logochanged fromstringtoLogoConfig,navigationchanged fromMenuItem[]toNavConfig.
logoprop restructured toLogoConfigobject (src,alt,width,text,textSize,textColor).navigationprop restructured toNavConfigobject (homeUrl,menuItems).classNamesprop introduced for CSS class injection (CustomClassNames).- Dual-theme support via
DualThemeConfig(light+dark).