Skip to main content

Overview

The navigation system provides a responsive, multi-level menu with icons, dropdown submenus, and mobile optimization. It integrates with Material Design Icons through astro-icon. The main navigation component with responsive design, dropdown menus, and integrated WhatsApp call-to-action.

Props

No props required - the component reads navigation data from @/data/menu.json.

Features

Dynamic Menu

Menu structure loaded from JSON configuration file for easy management.

Dropdown Submenus

Multi-level navigation with animated dropdowns and toggle buttons.

Icon Integration

Material Design Icons for visual navigation enhancement.

Mobile Responsive

Hamburger menu with slide-out navigation for mobile devices.

WhatsApp Integration

Direct WhatsApp contact buttons for desktop and mobile.

Highlight Markers

Visual indicators for featured menu items (e.g., special offers).

Usage

---
import NavBar from '@/components/NavBar.astro';
import Footer from '@/components/Footer.astro';
---

<!DOCTYPE html>
<html>
  <head>
    <title>My Site</title>
  </head>
  <body>
    <NavBar />
    <main>
      <slot />
    </main>
    <Footer />
  </body>
</html>
The navigation menu is configured through src/data/menu.json:
{
  "id": "4",
  "titulo": "BLOG",
  "link": "/blog/",
  "icon": "mdi:text-box-outline"
}
id
string
required
Unique identifier for the menu item. Use format like “1”, “2”, or “1-1” for submenu items.
titulo
string
required
Display text for the menu item. Typically uppercase for consistency.
URL path or external link for the menu item.
icon
string
Material Design Icon identifier (e.g., “mdi:view-grid”). Used for visual enhancement.
highlight
boolean
default:"false"
Whether to apply highlight styling. Used for promotional or important items.
submenu
array
Array of submenu items. Each submenu item should have id, titulo, and link properties.

Complete Example

[
  {
    "id": "1",
    "titulo": "SERVICIOS",
    "link": "/servicios/todos-los-servicios-web/",
    "icon": "mdi:view-grid",
    "submenu": [
      {
        "id": "1-1",
        "titulo": "DISEÑO WEB",
        "link": "/servicios/creacion-de-paginas-web/"
      },
      {
        "id": "1-2",
        "titulo": "TIENDAS ONLINE",
        "link": "/servicios/creacion-de-tiendas-online/"
      },
      {
        "id": "1-3",
        "titulo": "SEO Y MARKETING",
        "link": "/servicios/promocion-de-la-web/"
      }
    ]
  },
  {
    "id": "2",
    "titulo": "OFERTAS",
    "link": "/promociones/todas-las-promociones-web/",
    "icon": "mdi:tag",
    "highlight": true,
    "submenu": [
      {
        "id": "2-1",
        "titulo": "WEB ECONÓMICA",
        "link": "/promociones/web-onepage-en-oferta/"
      }
    ]
  },
  {
    "id": "3",
    "titulo": "BLOG",
    "link": "/blog/",
    "icon": "mdi:text-box-outline"
  }
]

Component Structure

Header Layout

<header>
  <!-- Logo -->
  <a href="/" class="logo">
    <img src="/img/logotipoAYW.webp" alt="Arte y Web Creaciones" />
  </a>
  
  <!-- Mobile WhatsApp Button -->
  <a href="https://wa.me/..." class="soloMovil header-whatsapp">
    <Icon name="mdi:whatsapp" />
  </a>
  
  <!-- Mobile Menu Toggle -->
  <input type="checkbox" id="menu-bar" />
  <label for="menu-bar">
    <Icon name="mdi:menu" />
  </label>
  
  <!-- Navigation Menu -->
  <nav class="navbar">
    <!-- Menu items -->
  </nav>
  
  <!-- Desktop WhatsApp Button -->
  <a href="https://wa.me/..." class="soloPC btn btn-verde">
    WhatsApp
  </a>
</header>
The component renders menu items dynamically:
<!-- Location: src/components/NavBar.astro:32-62 -->
<li id={item.id} class="menu-item">
  <a
    href={item.submenu ? "#" : item.link}
    class={`menu-link ${item.highlight ? "highlight-marker" : ""}`}
  >
    {item.icon && <Icon name={item.icon} class="menu-icon" />}
    <span class="menu-text">{item.titulo}</span>
    {item.submenu && <Icon name="mdi:chevron-down" class="dropdown-icon" />}
  </a>
  
  {item.submenu && (
    <>
      <button class="submenu-toggle" aria-label="Toggle submenu">
        <Icon name="mdi:chevron-down" />
      </button>
      <ul class="submenu hidden">
        {item.submenu.map((subitem) => (
          <li id={subitem.id}>
            <a href={subitem.link}>{subitem.titulo}</a>
          </li>
        ))}
      </ul>
    </>
  )}
</li>

Styling

The NavBar uses an external CSS file for styling:
<style>
  @import "../styles/NavBar.css";
</style>
The actual styling rules are maintained in src/styles/NavBar.css for better organization and reusability.

CSS Classes

  • .logo - Logo container with responsive sizing
  • .navbar - Main navigation container
  • .menu-item - Individual menu item wrapper
  • .menu-link - Clickable menu link
  • .menu-icon - Icon displayed before menu text
  • .dropdown-icon - Chevron icon for dropdown indicators
  • .submenu-toggle - Mobile submenu toggle button
  • .highlight-marker - Highlighted menu item styling
  • .hidden - Hidden submenu (toggled via JavaScript)
  • .visible - Visible submenu after toggle
  • .soloMovil - Visible only on mobile devices
  • .soloPC - Visible only on desktop devices

JavaScript Functionality

The component includes client-side JavaScript for interactive behavior:
// Location: src/components/NavBar.astro:85-96
menuLinks.forEach((link) => {
  link.addEventListener('click', (e) => {
    const submenu = link.nextElementSibling?.nextElementSibling;
    if (submenu && submenu.classList.contains('submenu')) {
      e.preventDefault();
      submenu.classList.toggle('visible');
    }
  });
});

Mobile Toggle Button

// Location: src/components/NavBar.astro:99-107
submenuToggles.forEach((toggle) => {
  toggle.addEventListener('click', (e) => {
    e.stopPropagation();
    const submenu = toggle.nextElementSibling;
    if (submenu && submenu.classList.contains('submenu')) {
      submenu.classList.toggle('visible');
    }
  });
});

Click Outside to Close

// Location: src/components/NavBar.astro:119-124
document.addEventListener('click', (e) => {
  const target = e.target;
  if (target && !target.closest('.menu-item')) {
    closeAllSubmenus();
  }
});

WhatsApp Integration

The NavBar includes two WhatsApp buttons with pre-filled messages:

Mobile Button

<!-- Location: src/components/NavBar.astro:16-24 -->
<a
  href="https://wa.me/34722201687?text=Hola,%20quiero%20mi%20presupuesto%20GRATIS%20en%2024h"
  class="soloMovil header-whatsapp"
  target="_blank"
  rel="noopener noreferrer"
  aria-label="Contactar por WhatsApp"
>
  <Icon name="mdi:whatsapp" class="text-3xl text-green-500" />
</a>

Desktop Button

<!-- Location: src/components/NavBar.astro:65-72 -->
<a
  href="https://wa.me/34722201687?text=Hola,%20quiero%20mi%20presupuesto%20GRATIS%20en%2024h"
  class="soloPC btn btn-verde"
  target="_blank"
  rel="noopener noreferrer"
>
  <Icon name="mdi:whatsapp" class="inline-block text-xl mr-1" /> WhatsApp
</a>
Customize the WhatsApp number and pre-filled message by editing the href attribute. The text is URL-encoded.

Icon Usage

The component uses astro-icon for Material Design Icons:

Available Icons

mdi:view-grid

Grid view (used for Services)

mdi:tag

Tag/label (used for Offers)

mdi:account-group

User group (used for About)

mdi:text-box-outline

Document (used for Blog)

mdi:calculator

Calculator (used for Quote)

mdi:whatsapp

WhatsApp logo

mdi:menu

Hamburger menu

mdi:chevron-down

Dropdown indicator

Adding Custom Icons

<Icon name="mdi:icon-name" class="custom-class" />
Browse available icons at Material Design Icons.

Customization Examples

Adding a New Menu Item

1

Update menu.json

Add a new entry to the menu configuration:
{
  "id": "6",
  "titulo": "PORTFOLIO",
  "link": "/portfolio/",
  "icon": "mdi:briefcase"
}
2

Verify Icon

Ensure the icon name exists in the Material Design Icons library.
3

Test Navigation

Refresh the page and verify the new menu item appears and functions correctly.

Creating a Mega Menu

For complex submenus with multiple columns:
{
  "id": "1",
  "titulo": "SERVICIOS",
  "link": "/servicios/",
  "icon": "mdi:view-grid",
  "submenu": [
    {
      "id": "1-1",
      "titulo": "DISEÑO WEB",
      "link": "/servicios/diseno-web/"
    },
    {
      "id": "1-2",
      "titulo": "E-COMMERCE",
      "link": "/servicios/tienda-online/"
    },
    {
      "id": "1-3",
      "titulo": "SEO",
      "link": "/servicios/seo/"
    },
    {
      "id": "1-4",
      "titulo": "MARKETING",
      "link": "/servicios/marketing/"
    },
    {
      "id": "1-5",
      "titulo": "HOSTING",
      "link": "/servicios/hosting/"
    },
    {
      "id": "1-6",
      "titulo": "MANTENIMIENTO",
      "link": "/servicios/mantenimiento/"
    }
  ]
}
For mega menus with more than 6 items, consider custom CSS to display in multiple columns.

Accessibility

  • Uses <header> for page header
  • <nav> for navigation container
  • Proper <ul> and <li> structure for menus
  • aria-label="Toggle submenu" on mobile toggle buttons
  • aria-label="Contactar por WhatsApp" on mobile WhatsApp button
  • All links and buttons are keyboard accessible
  • Submenu toggles work with Enter/Space keys
  • Focus indicators should be styled in CSS

Best Practices

Keep Menu Simple

Limit top-level items to 5-7 for optimal usability. Use submenus for additional pages.

Consistent Naming

Use consistent capitalization and terminology across menu items.

Icon Consistency

Choose icons that clearly represent their menu item and maintain a consistent style.

Test Mobile

Always test navigation on actual mobile devices, not just browser responsive mode.
  • Footer - Site footer with navigation links
  • Breadcrumbs - Breadcrumb navigation for page hierarchy
  • HeaderLink - Individual navigation link component

Source Code References

  • NavBar component: src/components/NavBar.astro:1-128
  • Menu data: src/data/menu.json
  • Styles: src/styles/NavBar.css

Build docs developers (and LLMs) love