UNIT 24 • STAGE 2 OF 7

Menu Cards

CSS Grid menu layout and data attributes on every card

UNIT 2 / 7
STEP 1

Why Data Attributes Matter

HTML has a feature called data attributes, custom attributes you invent yourself that start with data-. You can put any information on any element: data-category="starters", data-tab="mains", data-id="42".

Right now, all 12 menu cards will be visible at once; that's intentional. In Stage 3, JavaScript will read the data-category values and use them to show or hide cards when a tab button is clicked. You're setting up the data structure before you write the logic.

This is a pattern professionals use constantly: separate the data from the behavior.

STEP 2

Add the Menu Section CSS

Add this inside your existing <style> block, after the hero CSS:

👉 Add menu CSS: #menu { background: var(--cedar); padding: 80px 0; }
.menu-heading { font-family: var(--font-display); font-size: clamp(2rem, 4vw, 3rem); font-weight: 700; color: var(--cream); margin-bottom: 8px; }
.menu-sub { color: rgba(245,240,230,0.6); font-size: 1rem; margin-bottom: 40px; }
.tab-bar { display: flex; gap: 8px; margin-bottom: 40px; flex-wrap: wrap; }
.tab-btn { background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.15); color: rgba(245,240,230,0.7); padding: 10px 24px; border-radius: 100px; font-family: var(--font-body); font-size: 0.875rem; font-weight: 600; cursor: pointer; letter-spacing: 0.04em; transition: all 0.2s; }
.tab-btn.active { background: var(--ember); border-color: var(--ember); color: white; }
.menu-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; }
.menu-card { background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.1); border-radius: 12px; padding: 24px; }
.card-top { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 10px; }
.card-top h3 { font-family: var(--font-display); font-size: 1.25rem; font-weight: 600; color: var(--cream); }
.card-price { font-size: 1rem; font-weight: 700; color: var(--gold); white-space: nowrap; padding-left: 12px; }
.card-desc { font-size: 0.9rem; color: rgba(245,240,230,0.6); line-height: 1.6; margin-bottom: 14px; }
.card-badge { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ember); }
  • grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)), creates as many columns as fit, each at least 300px wide. Cards wrap automatically on smaller screens. No media queries needed.
  • background: rgba(255,255,255,0.06), a very faint white overlay on the dark cedar background. Gives cards just enough separation to read as distinct elements.
  • .tab-btn.active, this class does not exist in the HTML yet. JavaScript will add it when a button is clicked. The CSS is ready and waiting.
STEP 3

Add the Menu HTML

After the closing </section> of the hero, add the full menu section. Each card gets a data-category attribute:

👉 Tab buttons (add inside .tab-bar): <button class="tab-btn active" data-tab="starters">Starters</button>
<button class="tab-btn" data-tab="mains">Mains</button>
<button class="tab-btn" data-tab="sides">Sides</button>
<button class="tab-btn" data-tab="desserts">Desserts</button>
👉 Example card (repeat pattern for all 12): <div class="menu-card" data-category="starters">
  <div class="card-top">
    <h3>Fry Bread Bruschetta</h3>
    <span class="card-price">$14</span>
  </div>
  <p class="card-desc">Wild plum jam, smoked Lake Superior whitefish, cedar cream</p>
  <span class="card-badge">Starters</span>
</div>

All 12 cards are visible right now; that is correct

There is no JavaScript yet, so all cards show at once. In Stage 3, you will add JS that reads data-category and hides cards that do not match the active tab. Building the HTML structure before the behavior is the right order.

STEP 4

The Full Menu Item List

Use these 12 items, 3 per category:

  • Starters: Fry Bread Bruschetta $14, Three Sisters Soup $12, Walleye Fritters $16
  • Mains: Manoomin Bowl $28, Venison Loin $36, Cedar-Plank Salmon $32
  • Sides: Roasted Root Vegetables $10, Three Sisters Succotash $10, Traditional Frybread $8
  • Desserts: Maple Birch Pudding $12, Wild Berry Crisp $11, Wojapi Cup $10

Use data-category="starters", data-category="mains", data-category="sides", or data-category="desserts" on each card. The value must match the data-tab value on the button exactly.

Stage 2 Complete

You have 12 menu cards in a responsive CSS Grid, tab buttons with data-tab attributes, and each card labeled with data-category.

Next: Stage 3 adds JavaScript that makes the tabs actually work.

Code Editor
Live Preview