Skip to main content

Header Component Overview

The header is the first component users see. It contains the logo, search functionality, navigation links, and a shopping cart indicator. We’ll build it using Flexbox for layout and BEM methodology for naming.

Component Structure

<header class="header">
  <div class="header__container">
    <div class="header__logo">...</div>
    <div class="header__search">...</div>
    <nav class="header__nav">...</nav>
  </div>
  <div class="header__categories">...</div>
</header>

Building the HTML

1

Create the Header Element

Start with a semantic <header> element. Use the header class for styling and an ID for JavaScript access:
<header class="header" id="main-header">
  <div class="header__container">
    <!-- Content goes here -->
  </div>
</header>
BEM Block: header is the main block. All child elements will use header__ prefix.
2

Add the Logo

Create a clickable logo that links to the homepage:
<div class="header__logo">
  <a href="/" class="header__logo-link">
    <span class="header__logo-text">ML</span>
    <span class="header__logo-subtitle">Store</span>
  </a>
</div>
The logo uses two <span> elements so we can style them differently.
3

Build the Search Bar

Add a search form with input and button:
<div class="header__search">
  <form class="header__search-form" action="/buscar" method="GET">
    <input 
      type="search" 
      class="header__search-input" 
      placeholder="Buscar productos, marcas y más..." 
      name="q"
      id="search-input"
      autocomplete="off"
    />
    <button type="submit" class="header__search-button" aria-label="Buscar">
      <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
        <circle cx="11" cy="11" r="8"></circle>
        <path d="m21 21-4.35-4.35"></path>
      </svg>
    </button>
  </form>
</div>
Use type="search" instead of type="text" for better mobile keyboard and browser features.
4

Create Navigation Links

Add navigation using semantic <nav> and an unordered list:
<nav class="header__nav">
  <ul class="header__nav-list">
    <li class="header__nav-item">
      <a href="#" class="header__nav-link">Crear cuenta</a>
    </li>
    <li class="header__nav-item">
      <a href="#" class="header__nav-link">Ingresar</a>
    </li>
    <li class="header__nav-item">
      <a href="#" class="header__nav-link">Mis compras</a>
    </li>
    <li class="header__nav-item">
      <a href="#" class="header__nav-link header__nav-link--cart" data-cart-count="0">
        <!-- Cart SVG icon -->
        <span class="header__cart-label">Carrito</span>
      </a>
    </li>
  </ul>
</nav>
Notice the cart link has:
  • A modifier class: header__nav-link--cart
  • A data attribute: data-cart-count="0" (for the badge)
5

Add Category Bar

Add a secondary navigation below the main header:
<div class="header__categories">
  <nav class="header__categories-nav">
    <ul class="header__categories-list">
      <li class="header__categories-item">
        <a href="#" class="header__categories-link">Categorías</a>
      </li>
      <li class="header__categories-item">
        <a href="#" class="header__categories-link">Ofertas</a>
      </li>
      <!-- More categories -->
    </ul>
  </nav>
</div>

Styling with CSS

Main Header Block

.header {
  /* Gradient background (Mercado Libre style) */
  background: linear-gradient(
    to bottom, 
    var(--color-primary), 
    var(--color-primary-dark)
  );
  
  /* Sticky positioning: stays at top when scrolling */
  position: sticky;
  top: 0;
  z-index: 100;
  
  /* Subtle shadow for depth */
  box-shadow: var(--shadow-sm);
}
Sticky Positioning: The header behaves normally until you scroll past it, then it “sticks” to the top. The z-index: 100 ensures it stays above other content.

Flexbox Container

.header__container {
  /* Flexbox for horizontal layout */
  display: flex;
  align-items: center;        /* Vertical centering */
  justify-content: space-between; /* Logo left, nav right */
  gap: var(--spacing-md);     /* Space between items */
  
  /* Constrain width and center */
  max-width: var(--container-max-width);
  margin: 0 auto;
  padding: var(--spacing-md) var(--spacing-lg);
}
Flexbox Properties Explained:
  • display: flex - Activates flexbox layout
  • align-items: center - Centers children vertically
  • justify-content: space-between - Pushes first item left, last item right
  • gap - Adds space between flex items (cleaner than margin)

Logo Styling

.header__logo {
  flex-shrink: 0; /* Don't let the logo shrink */
}

.header__logo-link {
  display: flex;
  align-items: baseline; /* Align text baseline */
  gap: var(--spacing-xs);
  transition: transform var(--transition-fast);
}

.header__logo-link:hover {
  transform: scale(1.02); /* Subtle grow effect */
}

.header__logo-text {
  font-size: var(--font-size-2xl);
  font-weight: 700;
  color: var(--color-secondary);
}

.header__logo-subtitle {
  font-size: var(--font-size-lg);
  font-weight: 400;
  color: var(--color-gray-600);
}

Search Bar Styling

.header__search {
  flex: 1; /* Take all available space */
  max-width: 600px;
}

.header__search-form {
  display: flex;
  border-radius: var(--border-radius-sm);
  overflow: hidden; /* Makes children respect border-radius */
  box-shadow: var(--shadow-sm);
}

.header__search-input {
  flex: 1; /* Input takes remaining space */
  padding: var(--spacing-sm) var(--spacing-md);
  border: none;
  font-size: var(--font-size-base);
  min-width: 0; /* Important for flex items to shrink */
}

.header__search-input::placeholder {
  color: var(--color-gray-400);
}

.header__search-button {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--spacing-sm) var(--spacing-md);
  background-color: var(--color-secondary);
  color: var(--color-white);
  transition: background-color var(--transition-fast);
}

.header__search-button:hover {
  background-color: var(--color-secondary-dark);
}
overflow: hidden on the form makes the input and button respect the parent’s border-radius.
.header__nav {
  flex-shrink: 0; /* Don't shrink navigation */
}

.header__nav-list {
  display: flex;
  align-items: center;
  gap: var(--spacing-md);
}

.header__nav-link {
  display: flex;
  align-items: center;
  gap: var(--spacing-xs);
  padding: var(--spacing-xs) var(--spacing-sm);
  font-size: var(--font-size-sm);
  color: var(--color-gray-600);
  border-radius: var(--border-radius-sm);
  transition: background-color var(--transition-fast);
  white-space: nowrap; /* Prevent text wrapping */
}

.header__nav-link:hover {
  background-color: rgba(0, 0, 0, 0.05);
}

Cart Badge with CSS

.header__nav-link--cart {
  position: relative; /* For absolute positioning of badge */
}

/* Show badge only when count > 0 */
.header__nav-link--cart[data-cart-count]:not([data-cart-count="0"])::after {
  content: attr(data-cart-count); /* Read from data attribute */
  
  /* Position in top-right corner */
  position: absolute;
  top: -4px;
  right: -8px;
  
  /* Badge styling */
  min-width: 18px;
  height: 18px;
  padding: 0 var(--spacing-xs);
  background-color: var(--color-error);
  color: var(--color-white);
  font-size: var(--font-size-xs);
  font-weight: 600;
  border-radius: var(--border-radius-full);
  
  /* Center the number */
  display: flex;
  align-items: center;
  justify-content: center;
}
content: attr(data-cart-count) - This CSS reads the value from the HTML attribute and displays it. When JavaScript updates the attribute, the badge updates automatically!

Category Bar

.header__categories {
  background-color: var(--color-white);
  border-top: 1px solid rgba(0, 0, 0, 0.1);
}

.header__categories-nav {
  max-width: var(--container-max-width);
  margin: 0 auto;
  padding: 0 var(--spacing-lg);
}

.header__categories-list {
  display: flex;
  gap: var(--spacing-lg);
  overflow-x: auto; /* Allow horizontal scroll on mobile */
  -webkit-overflow-scrolling: touch; /* Smooth scroll on iOS */
  
  /* Hide scrollbar */
  scrollbar-width: none; /* Firefox */
  -ms-overflow-style: none; /* IE/Edge */
}

/* Hide scrollbar in Chrome/Safari */
.header__categories-list::-webkit-scrollbar {
  display: none;
}

.header__categories-link {
  display: block;
  padding: var(--spacing-sm) 0;
  font-size: var(--font-size-sm);
  color: var(--color-gray-500);
  white-space: nowrap;
  transition: color var(--transition-fast);
}

.header__categories-link:hover {
  color: var(--color-secondary);
}

Key Concepts Explained

BEM in Action

Notice how all classes follow the BEM pattern:
header                    (Block)
├── header__container     (Element)
├── header__logo          (Element)
│   ├── header__logo-link
│   ├── header__logo-text
│   └── header__logo-subtitle
├── header__search        (Element)
│   ├── header__search-form
│   ├── header__search-input
│   └── header__search-button
└── header__nav           (Element)
    ├── header__nav-list
    ├── header__nav-item
    └── header__nav-link--cart  (Modifier)

Flexbox Layout Strategy

The header uses Flexbox to create a responsive layout:
  1. Logo (flex-shrink: 0) - Never shrinks, maintains size
  2. Search (flex: 1) - Grows to fill available space
  3. Navigation (flex-shrink: 0) - Never shrinks, maintains size
This ensures the search bar is flexible while logo and nav remain constant.

Accessibility Features

Semantic HTML - Using <header>, <nav>, <form> for screen readers
aria-label - Describing the search button icon
Keyboard Navigation - All links and buttons are focusable
Focus Styles - Visible focus indicators (defined in global CSS)

Complete Header Code

See the full implementation:
  • HTML: /workspace/source/mi-tutorial/index.html:234-415
  • CSS: /workspace/source/mi-tutorial/src/style.css:452-832

Next Steps

Hero Section

Build an eye-catching hero banner with gradients

Shopping Cart

Learn how to update the cart badge dynamically

Build docs developers (and LLMs) love