DEV3 Technologies home

Restaurant menu card section

A two-column restaurant menu with category headings, dish names, descriptions, dotted price leaders and small dietary tags.

Tailwind CSSCardsmenurestaurantlayouttypography

Live preview

Code

<section class="mx-auto max-w-3xl px-6 py-12" aria-labelledby="menu-title">
  <h2 id="menu-title" class="text-center font-serif text-3xl text-stone-900">Our Menu</h2>
  <p class="mt-1 text-center text-sm text-stone-500">Prices in USD. Ask about allergens.</p>

  <div class="mt-10 grid gap-10 md:grid-cols-2">
    <div>
      <h3 class="mb-4 border-b-2 border-amber-600 pb-1 font-serif text-xl text-stone-900">Starters</h3>
      <ul class="space-y-4">
      <li class="flex items-baseline gap-3">
        <div class="min-w-0 flex-1">
          <h4 class="font-medium text-stone-900">Garden salad
          <span class="ml-2 rounded-full bg-emerald-100 px-2 py-0.5 text-[10px] font-semibold uppercase text-emerald-700">Vegan</span></h4>
          <p class="text-sm text-stone-500">Seasonal leaves, herbs, lemon dressing.</p>
        </div>
        <span class="mt-1 hidden h-px flex-1 border-b border-dotted border-stone-300 sm:block" aria-hidden="true"></span>
        <span class="font-semibold tabular-nums text-stone-900">$8</span>
      </li>
      <li class="flex items-baseline gap-3">
        <div class="min-w-0 flex-1">
          <h4 class="font-medium text-stone-900">Tomato soup</h4>
          <p class="text-sm text-stone-500">Roasted tomato, basil oil, toasted bread.</p>
        </div>
        <span class="mt-1 hidden h-px flex-1 border-b border-dotted border-stone-300 sm:block" aria-hidden="true"></span>
        <span class="font-semibold tabular-nums text-stone-900">$7</span>
      </li>
      </ul>
    </div>
    <div>
      <h3 class="mb-4 border-b-2 border-amber-600 pb-1 font-serif text-xl text-stone-900">Mains</h3>
      <ul class="space-y-4">
      <li class="flex items-baseline gap-3">
        <div class="min-w-0 flex-1">
          <h4 class="font-medium text-stone-900">Wood-fired pizza
          <span class="ml-2 rounded-full bg-emerald-100 px-2 py-0.5 text-[10px] font-semibold uppercase text-emerald-700">Veg</span></h4>
          <p class="text-sm text-stone-500">Mozzarella, tomato, fresh basil.</p>
        </div>
        <span class="mt-1 hidden h-px flex-1 border-b border-dotted border-stone-300 sm:block" aria-hidden="true"></span>
        <span class="font-semibold tabular-nums text-stone-900">$14</span>
      </li>
      <li class="flex items-baseline gap-3">
        <div class="min-w-0 flex-1">
          <h4 class="font-medium text-stone-900">Grilled salmon</h4>
          <p class="text-sm text-stone-500">Lemon butter, greens, new potatoes.</p>
        </div>
        <span class="mt-1 hidden h-px flex-1 border-b border-dotted border-stone-300 sm:block" aria-hidden="true"></span>
        <span class="font-semibold tabular-nums text-stone-900">$22</span>
      </li>
      </ul>
    </div>
  </div>
</section>

How it works

What it solves

Restaurant menus are lists of short items with prices, and the layout cues people expect are the category headings and the dotted line that links a dish to its price. This section reproduces that look with a few utilities and stays readable on phones.

How it works

The section is a single column on phones and a two-column grid from md. Each category has a serif heading with an amber underline, followed by a ul of dishes. Every dish is a flex row: a text block that can shrink (min-w-0 flex-1), a decorative dotted leader and the price. The leader is a zero-height element with border-dotted and flex-1, so it expands to fill whatever space is left between name and price, then disappears on the smallest screens to avoid cramped lines. tabular-nums aligns digits when prices stack.

Dietary tags are small pill badges after the name. The leader is hidden from assistive tools with aria-hidden, so a screen reader hears just dish, description and price.

Adapting it

  • Generate categories and dishes from your menu data in loops.
  • Change the amber underline and pill colours to match your brand.
  • Add a currency formatter on the server instead of typing symbols.

Pitfalls

  • Keep descriptions to a line or two; long ones break the rhythm of the leaders.
  • Always list allergens in text, not only with colour or icons.
  • Update prices in one data source so the printed and online menus match.

How to use it

  1. Add the section to your menu page and load Tailwind CSS 4.
  2. Loop each category and dish from your data into the same markup.
  3. Format prices on the server and keep the price span last in each row.
  4. Add or remove tag pills with a conditional per dish.

Licence: DEV3 Snippet Licence. Free to use, change and ship in personal and commercial projects. Attribution is appreciated, not required. Please do not redistribute snippets as a collection.

Related snippets