@manufosela/header-nav

@manufosela/header-nav

Responsive header navigation web component with hamburger menu

Header Nav

Responsive header navigation with hamburger menu and sticky option.

Tip: Resize your browser window to see the responsive hamburger menu. Nav links use event.preventDefault() in this demo so clicking them won't scroll the page.

Basic Usage

Responsive header with navigation links.

<header-nav logo="logo.svg"> <a href="/home">Home</a> <a href="/about">About</a> <a href="/services">Services</a> <a href="/contact">Contact</a> </header-nav>

Text Logo

Using a text-based logo with the slot.

<header-nav> <span slot="logo-text" style="font-size:1.3rem;font-weight:bold;color:#6366f1">MyBrand</span> <a href="/products">Products</a> <a href="/pricing">Pricing</a> <a href="/docs">Docs</a> </header-nav>

Custom Styling

Use CSS custom properties for theming.

<style> .my-header { --header-bg: #1e293b; --header-text: #e2e8f0; --header-link-hover: #38bdf8; } </style> <header-nav logo="logo.svg" class="my-header"> <a href="/home">Home</a> <a href="/features">Features</a> <a href="/pricing">Pricing</a> <a href="/blog">Blog</a> </header-nav>

Taller Header

Customize header height.

<header-nav logo="logo.svg" style="--header-height: 80px;"> <a href="#section1">Section 1</a> <a href="#section2">Section 2</a> <a href="#section3">Section 3</a> </header-nav>

Custom Breakpoint

Change when the hamburger menu appears.

<header-nav logo="logo.svg" mobile-breakpoint="1200"> <a href="/home">Home</a> <a href="/about">About</a> <a href="/services">Services</a> <a href="/portfolio">Portfolio</a> <a href="/blog">Blog</a> <a href="/contact">Contact</a> </header-nav>

Active State

Click a nav link to see the active highlight. The nav-click event fires with the link details.

Active: Dashboard (index 0)
<header-nav active-index="0"> <a href="/dashboard">Dashboard</a> <a href="/projects">Projects</a> <a href="/team">Team</a> <a href="/settings">Settings</a> </header-nav> <script> nav.addEventListener('nav-click', (e) => { console.log('Clicked:', e.detail.text, 'index:', e.detail.index); }); </script>

Disabled Links + Interactive Controls

Use setDisabled(index, true/false) to enable/disable nav items programmatically.

const nav = document.querySelector('header-nav'); // Disable a link by index nav.setDisabled(2, true); // "Admin" becomes greyed out // Enable it back nav.setDisabled(2, false); // Set active programmatically nav.activeIndex = 0; // "Home" becomes active

Event Handling

Listen for menu toggle and nav click events.

Click a link or toggle the menu...
<script> nav.addEventListener('nav-click', (e) => { console.log('Clicked:', e.detail.text, 'at index', e.detail.index); }); nav.addEventListener('menu-toggle', (e) => { console.log('Menu:', e.detail.open ? 'open' : 'closed'); }); </script>
Demo code (CodePen-ready HTML, CSS, JS)
HTML (html)
<div class="page-content">
    <h1>Header Nav</h1>
    <p class="subtitle">Responsive header navigation with hamburger menu and sticky option.</p>
    <div class="demo-links">
      <a href="https://manufosela.dev/ui-components/">← Back to components</a>
      <a href="https://github.com/manufosela/ui-components/tree/main/packages/header-nav" target="_blank" rel="noopener">GitHub Repo</a>
      <a href="playground.html">Playground</a>
      <a href="https://www.npmjs.com/package/@manufosela/header-nav" target="_blank" rel="noopener">npm</a>
    </div>
    <div class="demo-theme-toggle">
      <theme-toggle theme="dark"></theme-toggle>
    </div>
    <div class="note">
      <strong>Tip:</strong> Resize your browser window to see the responsive hamburger menu. Nav links use <code>event.preventDefault()</code> in this demo so clicking them won't scroll the page.
    </div>

    <div class="demo-section">
      <h2>Basic Usage</h2>
      <p>Responsive header with navigation links.</p>
      <div class="demo-header">
        <header-nav logo="logo.svg" style="--header-bg:#1e293b; --header-link-color:#94a3b8; --header-link-hover:#f1f5f9;">
          <a href="#home">Home</a>
          <a href="#about">About</a>
          <a href="#services">Services</a>
          <a href="#contact">Contact</a>
        </header-nav>
      </div>
      <div class="code-block">&lt;header-nav logo="logo.svg"&gt;
  &lt;a href="/home"&gt;Home&lt;/a&gt;
  &lt;a href="/about"&gt;About&lt;/a&gt;
  &lt;a href="/services"&gt;Services&lt;/a&gt;
  &lt;a href="/contact"&gt;Contact&lt;/a&gt;
&lt;/header-nav&gt;</div>
    </div>

    <div class="demo-section">
      <h2>Text Logo</h2>
      <p>Using a text-based logo with the slot.</p>
      <div class="demo-header">
        <header-nav>
          <span slot="logo-text" style="font-size:1.3rem;font-weight:bold;color:#6366f1">MyBrand</span>
          <a href="#products">Products</a>
          <a href="#pricing">Pricing</a>
          <a href="#docs">Docs</a>
        </header-nav>
      </div>
      <div class="code-block">&lt;header-nav&gt;
  &lt;span slot="logo-text" style="font-size:1.3rem;font-weight:bold;color:#6366f1"&gt;MyBrand&lt;/span&gt;
  &lt;a href="/products"&gt;Products&lt;/a&gt;
  &lt;a href="/pricing"&gt;Pricing&lt;/a&gt;
  &lt;a href="/docs"&gt;Docs&lt;/a&gt;
&lt;/header-nav&gt;</div>
    </div>

    <div class="demo-section">
      <h2>Custom Styling</h2>
      <p>Use CSS custom properties for theming.</p>
      <div class="demo-header">
        <header-nav logo="logo.svg" style="--header-bg:#1e293b; --header-text:#e2e8f0; --header-link-hover:#38bdf8;">
          <a href="#home">Home</a>
          <a href="#features">Features</a>
          <a href="#pricing">Pricing</a>
          <a href="#blog">Blog</a>
        </header-nav>
      </div>
      <div class="code-block">&lt;style&gt;
  .my-header {
    --header-bg: #1e293b;
    --header-text: #e2e8f0;
    --header-link-hover: #38bdf8;
  }
&lt;/style&gt;

&lt;header-nav logo="logo.svg" class="my-header"&gt;
  &lt;a href="/home"&gt;Home&lt;/a&gt;
  &lt;a href="/features"&gt;Features&lt;/a&gt;
  &lt;a href="/pricing"&gt;Pricing&lt;/a&gt;
  &lt;a href="/blog"&gt;Blog&lt;/a&gt;
&lt;/header-nav&gt;</div>
    </div>

    <div class="demo-section">
      <h2>Taller Header</h2>
      <p>Customize header height.</p>
      <div class="demo-header">
        <header-nav logo="logo.svg" style="--header-height:80px; --header-bg:#1e293b; --header-link-color:#94a3b8; --header-link-hover:#f1f5f9;">
          <a href="#section1">Section 1</a>
          <a href="#section2">Section 2</a>
          <a href="#section3">Section 3</a>
        </header-nav>
      </div>
      <div class="code-block">&lt;header-nav logo="logo.svg" style="--header-height: 80px;"&gt;
  &lt;a href="#section1"&gt;Section 1&lt;/a&gt;
  &lt;a href="#section2"&gt;Section 2&lt;/a&gt;
  &lt;a href="#section3"&gt;Section 3&lt;/a&gt;
&lt;/header-nav&gt;</div>
    </div>

    <div class="demo-section">
      <h2>Custom Breakpoint</h2>
      <p>Change when the hamburger menu appears.</p>
      <div class="demo-header">
        <header-nav logo="logo.svg" mobile-breakpoint="1200" style="--header-bg:#1e293b; --header-link-color:#94a3b8; --header-link-hover:#f1f5f9;">
          <a href="#home">Home</a>
          <a href="#about">About</a>
          <a href="#services">Services</a>
          <a href="#portfolio">Portfolio</a>
          <a href="#blog">Blog</a>
          <a href="#contact">Contact</a>
        </header-nav>
      </div>
      <div class="code-block">&lt;header-nav logo="logo.svg" mobile-breakpoint="1200"&gt;
  &lt;a href="/home"&gt;Home&lt;/a&gt;
  &lt;a href="/about"&gt;About&lt;/a&gt;
  &lt;a href="/services"&gt;Services&lt;/a&gt;
  &lt;a href="/portfolio"&gt;Portfolio&lt;/a&gt;
  &lt;a href="/blog"&gt;Blog&lt;/a&gt;
  &lt;a href="/contact"&gt;Contact&lt;/a&gt;
&lt;/header-nav&gt;</div>
    </div>

    <div class="demo-section">
      <h2>Active State</h2>
      <p>Click a nav link to see the active highlight. The <code>nav-click</code> event fires with the link details.</p>
      <div class="demo-header">
        <header-nav id="activeDemo" logo="logo.svg" active-index="0" style="--header-bg:#1e293b; --header-link-color:#94a3b8; --header-link-hover:#f1f5f9; --header-link-active:#38bdf8; --header-link-active-bg:rgba(56,189,248,0.15);">
          <a href="#dashboard">Dashboard</a>
          <a href="#projects">Projects</a>
          <a href="#team">Team</a>
          <a href="#settings">Settings</a>
        </header-nav>
      </div>
      <div id="activeOutput" style="margin-top:1rem; padding:1rem; background:var(--demo-event-bg); border-radius:8px; font-family:monospace; color:var(--demo-muted);">
        Active: Dashboard (index 0)
      </div>
      <div class="code-block">&lt;header-nav active-index="0"&gt;
  &lt;a href="/dashboard"&gt;Dashboard&lt;/a&gt;
  &lt;a href="/projects"&gt;Projects&lt;/a&gt;
  &lt;a href="/team"&gt;Team&lt;/a&gt;
  &lt;a href="/settings"&gt;Settings&lt;/a&gt;
&lt;/header-nav&gt;

&lt;script&gt;
  nav.addEventListener('nav-click', (e) =&gt; {
    console.log('Clicked:', e.detail.text, 'index:', e.detail.index);
  });
&lt;/script&gt;</div>
    </div>

    <div class="demo-section">
      <h2>Disabled Links + Interactive Controls</h2>
      <p>Use <code>setDisabled(index, true/false)</code> to enable/disable nav items programmatically.</p>
      <div class="demo-header">
        <header-nav id="disabledDemo" logo="logo.svg" active-index="0" style="--header-bg:#1e293b; --header-link-color:#94a3b8; --header-link-hover:#f1f5f9; --header-link-active:#22c55e; --header-link-active-bg:rgba(34,197,94,0.15);">
          <a href="#home">Home</a>
          <a href="#profile">Profile</a>
          <a href="#admin">Admin</a>
          <a href="#logout">Logout</a>
        </header-nav>
      </div>
      <div style="margin-top:1rem; display:flex; gap:0.5rem; flex-wrap:wrap;">
        <button onclick="document.getElementById('disabledDemo').setDisabled(2, true)" style="padding:0.4rem 1rem; border:1px solid var(--demo-border); background:var(--demo-card-bg); color:var(--demo-text); border-radius:6px; cursor:pointer;">Disable "Admin"</button>
        <button onclick="document.getElementById('disabledDemo').setDisabled(2, false)" style="padding:0.4rem 1rem; border:1px solid var(--demo-border); background:var(--demo-card-bg); color:var(--demo-text); border-radius:6px; cursor:pointer;">Enable "Admin"</button>
        <button onclick="document.getElementById('disabledDemo').activeIndex = 2; document.getElementById('disabledDemo')._updateActiveState()" style="padding:0.4rem 1rem; border:1px solid var(--demo-border); background:var(--demo-card-bg); color:var(--demo-text); border-radius:6px; cursor:pointer;">Activate "Admin"</button>
      </div>
      <div class="code-block">const nav = document.querySelector('header-nav');

// Disable a link by index
nav.setDisabled(2, true);   // "Admin" becomes greyed out

// Enable it back
nav.setDisabled(2, false);

// Set active programmatically
nav.activeIndex = 0;        // "Home" becomes active</div>
    </div>

    <div class="demo-section">
      <h2>Event Handling</h2>
      <p>Listen for menu toggle and nav click events.</p>
      <div class="demo-header">
        <header-nav id="eventDemo" logo="logo.svg" style="--header-bg:#1e293b; --header-link-color:#94a3b8; --header-link-hover:#f1f5f9;">
          <a href="#link1">Link 1</a>
          <a href="#link2">Link 2</a>
          <a href="#link3">Link 3</a>
        </header-nav>
      </div>
      <div id="eventOutput" style="margin-top:1rem; padding:1rem; background:var(--demo-event-bg); border-radius:8px; font-family:monospace; color:var(--demo-muted); min-height:2rem;">
        Click a link or toggle the menu...
      </div>
      <div class="code-block">&lt;script&gt;
  nav.addEventListener('nav-click', (e) =&gt; {
    console.log('Clicked:', e.detail.text, 'at index', e.detail.index);
  });
  nav.addEventListener('menu-toggle', (e) =&gt; {
    console.log('Menu:', e.detail.open ? 'open' : 'closed');
  });
&lt;/script&gt;</div>
    </div>

    
  </div>
CSS (css)
:root {
  --bg: #0c0f14;
  --bg-elevated: #141923;
  --bg-panel: #171d28;
  --border: #262f3f;
  --text: #f4f6fb;
  --text-muted: #a7b0c2;
  --text-dim: #7d879b;
  --accent: #ff8a3d;
  --accent-strong: #ff6a00;
  --accent-soft: rgba(255, 138, 61, 0.16);
  --shadow: 0 20px 50px rgba(5, 8, 14, 0.45);
  --radius-lg: 22px;
  --radius-md: 14px;
  --radius-sm: 10px;
  --max-width: 1160px;
}

:root {
      --demo-bg: #f5f5f7;
      --demo-card-bg: #ffffff;
      --demo-text: #1d1d1f;
      --demo-muted: #86868b;
      --demo-border: #d2d2d7;
      --demo-code-bg: #1d1d1f;
      --demo-code-text: #f5f5f7;
      --demo-note-bg: #fef3c7;
      --demo-note-border: #f59e0b;
      --demo-event-bg: #f5f5f7;
    }
    :root.dark {
      --demo-bg: #0f1117;
      --demo-card-bg: #1c2233;
      --demo-text: #f3f6ff;
      --demo-muted: #b8c0d9;
      --demo-border: #2b3247;
      --demo-code-bg: #0b0f1a;
      --demo-code-text: #d6d9e6;
      --demo-note-bg: rgba(245, 158, 11, 0.1);
      --demo-note-border: #f59e0b;
      --demo-event-bg: #1c2233;
    }
    .page-content {
      max-width: 900px;
      margin: 0 auto;
      padding: 2rem;
    }
    h1 { color: var(--demo-text); }
    .demo-section {
      background: var(--demo-card-bg);
      padding: 2rem;
      border-radius: 12px;
      margin-bottom: 2rem;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    h2 { margin-top: 0; color: var(--demo-text); }
    p { color: var(--demo-muted); line-height: 1.6; }
    .code-block {
      background: var(--demo-code-bg);
      color: var(--demo-code-text);
      padding: 1rem;
      border-radius: 8px;
      font-family: monospace;
      font-size: 0.8rem;
      margin-top: 1rem;
      overflow-x: auto;
      white-space: pre;
    }
    .demo-header {
      margin: 0 -2rem;
      margin-top: -2rem;
      margin-bottom: 1rem;
      border-radius: 12px 12px 0 0;
      overflow: hidden;
    }
    .note {
      background: var(--demo-note-bg);
      border-left: 4px solid var(--demo-note-border);
      padding: 1rem;
      margin: 1rem 0;
      border-radius: 0 8px 8px 0;
      color: var(--demo-text);
    }
    footer {
      text-align: center;
      margin-top: 3rem;
      padding-top: 2rem;
      border-top: 1px solid var(--demo-border);
      color: var(--demo-muted);
      font-size: 0.9rem;
    }
    footer a { color: var(--demo-text); text-decoration: none; }
    footer a:hover { text-decoration: underline; }
  


@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;600;700&display=swap');

:root {
  --bg: #f5f5f7;
  --bg-2: #ffffff;
  --bg-spot-1: #f8e9d0;
  --bg-spot-2: #e8eef8;
  --card: #ffffff;
  --text: #1d1d1f;
  --muted: #6b7280;
  --line: #e5e7eb;
  --accent: #ffb000;
  --accent-2: #00a7d6;
  --accent-soft: rgba(255, 176, 0, 0.18);
  --surface-1: #f3f4f6;
  --surface-2: #eef2f7;
  --code-bg: #111827;
  --code-text: #f9fafb;
  --panel-bg: rgba(255, 255, 255, 0.85);
  --overlay-bg: rgba(255, 255, 255, 0.98);
}

:root.dark {
  --bg: #0f1117;
  --bg-2: #151a26;
  --bg-spot-1: #1a2136;
  --bg-spot-2: #1d1b34;
  --card: #1c2233;
  --text: #f3f6ff;
  --muted: #b8c0d9;
  --line: #2b3247;
  --accent: #ffb000;
  --accent-2: #00d0ff;
  --accent-soft: rgba(255, 176, 0, 0.25);
  --surface-1: #0b0f1a;
  --surface-2: #263046;
  --code-bg: #0b0f1a;
  --code-text: #d6d9e6;
  --panel-bg: rgba(28, 34, 51, 0.8);
  --overlay-bg: rgba(15, 17, 23, 0.98);
}

* {
  box-sizing: border-box;
}

a {
  color: var(--accent);
}

h1 {
  color: var(--accent);
}

.demo-links {
  margin-top: 12px;
  display: flex;
  gap: 12px;
  justify-content: center;
  flex-wrap: wrap;
}

.demo-links a {
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 6px 12px;
  color: var(--muted);
  text-decoration: none;
  font-size: 0.85rem;
  transition: border-color 0.2s ease, color 0.2s ease;
}

.demo-links a:hover {
  color: var(--text);
  border-color: var(--accent-2);
}

.demo-theme-toggle {
  margin-top: 12px;
  display: flex;
  justify-content: center;
}

header {
  border-bottom: 1px solid var(--line);
}

.demo-card,
.section,
.demo-section,
.panel,
.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 16px;
  color: var(--text);
  box-shadow: 0 18px 36px rgba(6, 10, 24, 0.45);
}

.demo-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.demo-card .code-block {
  margin-top: auto;
}

.demo-grid,
.grid {
  align-items: stretch;
}

.demo-card h2,
.demo-card h3,
.section h2,
.demo-section h2,
.panel-header {
  color: var(--text);
}

.label,
.stat-label,
.category-title,
.subtitle,
.hint,
.note {
  color: var(--muted);
}

.info-item,
.capability,
.preference,
.option-group,
.output,
.current-url,
.event-log,
.result-card,
.log,
.stat {
  background: var(--surface-1);
  border: 1px solid var(--line);
  color: var(--text);
}

.info-item .label,
.capability .name {
  color: var(--muted);
}

.panel-header,
.options,
.topbar,
.top-links {
  background: var(--panel-bg);
  border-bottom: 1px solid var(--line);
  color: var(--text);
}

.subtitle,
.hint,
.note,
.demo-card p,
.section p,
.demo-section p {
  color: var(--muted);
}

.code-block,
pre,
code {
  background: var(--code-bg);
  color: var(--code-text);
  border-radius: 8px;
}

.value-display,
.output,
.result,
.demo-output {
  background: var(--surface-1);
  border: 1px solid var(--line);
  color: var(--text);
}

button {
  background: linear-gradient(120deg, var(--accent), #ff6a00);
  color: #111;
  border: none;
}

button:hover {
  filter: brightness(1.05);
}

input,
select,
textarea {
  background: var(--surface-1);
  color: var(--text);
  border: 1px solid var(--line);
}

footer {
  color: var(--muted);
}

footer a {
  color: var(--text);
}

arc-slider {
  --arc-slider-text-color: var(--text);
  --arc-slider-value-bg: var(--surface-1);
  --arc-slider-value-border: var(--line);
  --arc-slider-value-shadow: 0 6px 16px rgba(0, 0, 0, 0.35);
}

rich-select {
  --caller-background: var(--card);
  --caller-color: var(--text);
  --caller-border: 1px solid var(--line);
  --caller-hover-background: var(--surface-2);
  --caller-hover-color: var(--text);
  --caller-hover-border-color: var(--line);
  --caller-focus-border-color: var(--accent-2);
  --caller-focus-shadow: 0 0 0 3px rgba(0, 208, 255, 0.25);
  --caller-disabled-background: var(--surface-1);
  --caller-disabled-color: #6b7280;
  --caller-disabled-border-color: var(--line);
  --arrow-color: var(--muted);
  --selectOptions-background: var(--card);
  --selectOptions-border: 1px solid var(--line);
  --selectOptions-shadow: 0 10px 22px rgba(0, 0, 0, 0.45);
  --input-background: var(--surface-1);
  --input-border: 1px solid var(--line);
  --input-color: var(--text);
  --input-placeholder-color: #6b7280;
  --option-color: var(--text);
  --option-hover-background: var(--surface-2);
  --option-hover-color: var(--text);
  --option-active-background: var(--accent);
  --option-active-color: #111;
  --option-selected-background: var(--accent-soft);
  --option-selected-color: var(--text);
  --option-disabled-background: var(--surface-1);
  --option-disabled-color: #6b7280;
}

multi-select {
  --multi-select-bg: var(--card);
  --multi-select-border-color: var(--line);
  --multi-select-border-hover: var(--line);
  --multi-select-border-focus: var(--accent-2);
  --multi-select-text-color: var(--text);
  --multi-select-placeholder-color: #6b7280;
  --multi-select-arrow-color: var(--muted);
  --multi-select-dropdown-bg: var(--card);
  --multi-select-shadow: 0 10px 22px rgba(0, 0, 0, 0.45);
  --multi-select-option-hover-bg: var(--surface-2);
  --multi-select-option-selected-bg: var(--accent-soft);
}

tab-nav {
  --tab-bg: var(--card);
  --tab-border: var(--line);
  --tab-text: var(--muted);
  --tab-active-text: var(--text);
  --tab-hover-bg: var(--surface-2);
  --tab-active-border: var(--accent);
  --tab-disabled: #9ca3af;
}

slider-underline {
  --slider-track: var(--surface-2);
  --slider-fill: var(--accent);
  --slider-thumb: var(--accent);
  --slider-label-color: var(--text);
  --slider-tick-color: #9ca3af;
  --slider-tick-value-color: var(--muted);
}

header-nav {
  --header-bg: var(--card);
  --header-shadow: 0 12px 24px rgba(0, 0, 0, 0.2);
  --header-link-color: var(--text);
  --header-link-hover: var(--accent);
  --header-mobile-hover-bg: var(--surface-2);
}

calendar-inline {
  --calendar-bg: var(--card);
  --calendar-shadow: 0 12px 24px rgba(0, 0, 0, 0.2);
  --calendar-text: var(--text);
  --calendar-accent: var(--accent);
  --calendar-today: var(--accent-soft);
  --calendar-selected: var(--accent);
  --calendar-hover-bg: var(--surface-2);
  --calendar-muted: var(--muted);
  --calendar-muted-strong: #9ca3af;
  --calendar-other-month: #9ca3af;
  --calendar-disabled: #cbd5e1;
  --calendar-holiday: #ef4444;
  --calendar-holiday-selected: #111;
}

marked-calendar {
  --calendar-bg: var(--card);
  --calendar-border: var(--line);
  --calendar-title: var(--text);
  --calendar-muted: var(--muted);
  --calendar-surface: var(--surface-1);
  --calendar-accent: var(--accent);
  --calendar-accent-hover: #ff7a1a;
  --calendar-border-strong: var(--line);
  --calendar-contrast: #111;
  --calendar-nav-bg: var(--surface-1);
  --calendar-nav-hover: var(--surface-2);
}

radar-chart {
  --radar-bg: var(--card);
  --radar-grid-color: var(--line);
  --radar-axis-color: #94a3b8;
  --radar-label-color: var(--muted);
}

multi-carousel {
  --carousel-bg: var(--card);
  --carousel-arrow-bg: var(--surface-1);
  --carousel-arrow-color: var(--text);
  --carousel-arrow-hover-bg: var(--surface-2);
  --carousel-arrow-hover-color: var(--text);
  --carousel-nav-bg: var(--surface-1);
  --carousel-nav-color: var(--muted);
  --carousel-nav-hover: #9ca3af;
  --carousel-nav-active: var(--accent);
  --carousel-focus-color: var(--accent-2);
}

nav-list {
  --nav-list-bg: var(--card);
  --nav-list-border-color: var(--line);
  --nav-list-selected-border-color: var(--accent);
  --nav-list-selected-bg: var(--surface-2);
  --nav-list-hover-bg: var(--surface-2);
  --nav-list-selected-color: var(--text);
}

theme-toggle {
  --theme-toggle-bg: var(--card);
  --theme-toggle-icon-color: var(--muted);
  --theme-toggle-hover-bg: var(--surface-2);
  --theme-toggle-active-bg: var(--surface-1);
  --theme-toggle-active-color: var(--text);
  --theme-toggle-dark-bg: var(--card);
  --theme-toggle-dark-border: var(--line);
  --theme-toggle-dark-icon-color: var(--muted);
  --theme-toggle-dark-active-bg: var(--surface-1);
  --theme-toggle-dark-active-color: var(--text);
  --theme-toggle-dark-hover-bg: var(--surface-2);
}

qr-code {
  --qr-fg: #0f1117;
  --qr-bg: #f3f6ff;
}

click-clock {
  --clock-color: var(--text);
  --clock-bg: var(--card);
  --clock-muted-color: var(--muted);
}

historical-line {
  --title-color: var(--text);
  --border-color: var(--line);
  --year-bg: var(--surface-1);
}

circle-steps {
  --steps-muted: var(--muted);
  --steps-text: var(--text);
  --steps-pending: var(--surface-2);
}

rich-inputfile {
  --input-border: var(--line);
  --input-border-focus: var(--accent-2);
  --input-bg: var(--card);
  --input-label-color: var(--text);
  --input-hover-bg: var(--surface-2);
  --input-drag-bg: var(--accent-soft);
  --input-disabled-bg: var(--surface-1);
  --input-success-border: #22c55e;
  --input-success-bg: rgba(34, 197, 94, 0.12);
  --input-icon-color: #94a3b8;
  --input-text-color: var(--muted);
  --input-accent-color: var(--accent-2);
  --input-file-bg: var(--surface-1);
  --input-preview-bg: var(--surface-1);
  --input-file-name-color: var(--text);
  --input-file-size-color: var(--muted);
  --input-error-color: #ef4444;
  --input-hint-color: var(--muted);
}

data-card {
  --data-card-bg: var(--card);
  --data-card-border-color: var(--line);
  --data-card-title-color: var(--text);
  --data-card-desc-color: var(--muted);
  --data-card-info-bg: var(--overlay-bg);
  --data-card-info-close-bg: var(--surface-2);
  --data-card-info-close-color: var(--text);
  --data-card-info-close-hover-bg: var(--surface-1);
  --data-card-info-text: var(--text);
  --data-card-loading-color: var(--muted);
  --data-card-info-trigger-hover: var(--accent);
}

app-modal {
  --app-modal-bg: var(--card);
  --app-modal-body-color: var(--text);
  --app-modal-standalone-bg: rgba(255, 176, 0, 0.35);
  --app-modal-standalone-color: #111;
  --app-modal-standalone-hover-bg: rgba(255, 176, 0, 0.6);
}
JS (js)
document.querySelectorAll('.footer-year').forEach(el => el.textContent = new Date().getFullYear());

    // Prevent demo nav links from scrolling to top
    document.querySelectorAll('header-nav a[href^="#"]').forEach(link => {
      link.addEventListener('click', (e) => e.preventDefault());
    });
  

    import "https://esm.sh/@manufosela/header-nav";

    // Active state demo
    const activeDemo = document.getElementById('activeDemo');
    const activeOutput = document.getElementById('activeOutput');
    activeDemo.addEventListener('nav-click', (e) => {
      activeOutput.textContent = `Active: ${e.detail.text} (index ${e.detail.index})`;
    });

    // Disabled demo — disable "Admin" by default
    const disabledDemo = document.getElementById('disabledDemo');
    disabledDemo.updateComplete.then(() => {
      disabledDemo.setDisabled(2, true);
    });

    // Event handling demo
    const eventDemo = document.getElementById('eventDemo');
    const eventOutput = document.getElementById('eventOutput');

    const logEvent = (msg) => {
      const line = document.createElement('div');
      line.textContent = msg;
      eventOutput.prepend(line);
      if (eventOutput.children.length > 5) eventOutput.lastChild.remove();
    };

    eventDemo.addEventListener('nav-click', (e) => {
      logEvent(`nav-click → "${e.detail.text}" (index ${e.detail.index})`);
    });
    eventDemo.addEventListener('menu-toggle', (e) => {
      logEvent(`menu-toggle → ${e.detail.open ? 'open' : 'closed'}`);
    });
  

    import '../../theme-toggle/src/theme-toggle.js';

    const root = document.documentElement;

    const toggle = document.querySelector('theme-toggle');
    if (toggle) {
      toggle.theme = root.classList.contains('dark') ? 'dark' : 'light';
      toggle.addEventListener('theme-changed', (event) => {
        const theme = event.detail?.theme;
        if (!theme) return;
        root.classList.toggle('dark', theme === 'dark');
      });
    }