A cafe menu template you can share as a link

A cafe menu can be one web page: section headings, one line per item with its price. Ask an AI to build it, then share it as a link that every profile can use.

A cafe menu template can be a single web page: a heading for each section, then one line per item with the price on the right.

People ask "Is there any free digital menu software out there?", but a small menu does not need software. One page is enough, and one link carries it to every profile.

Here is a complete example. Tap the section buttons at the top. Notice the sold-out line and the dollar prices.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Juniper Lane Cafe - Menu</title>
<style>
  * { box-sizing: border-box; }
  html { scroll-behavior: smooth; }
  body { margin: 0; font-family: Georgia, "Times New Roman", serif; background: #faf6ef; color: #2b2118; font-size: 17px; line-height: 1.5; }
  header { padding: 26px 20px 14px; text-align: center; }
  header h1 { margin: 0; font-size: 28px; letter-spacing: .5px; }
  header p { margin: 4px 0 0; font: 14px system-ui, sans-serif; color: #7a6a58; }
  nav { position: sticky; top: 0; background: #faf6ef; padding: 10px 14px; display: flex; gap: 8px; overflow-x: auto; border-bottom: 1px solid #e6dccb; }
  nav a { flex: none; font: 600 14px system-ui, sans-serif; color: #5a3d22; text-decoration: none; padding: 7px 14px; border: 1px solid #d9c9b0; border-radius: 999px; background: #fff; }
  main { max-width: 560px; margin: 0 auto; padding: 8px 20px 40px; }
  section { padding-top: 22px; }
  h2 { margin: 0 0 6px; font-size: 21px; color: #7a3e12; border-bottom: 2px solid #e6dccb; padding-bottom: 6px; }
  .item { display: flex; justify-content: space-between; gap: 16px; padding: 10px 0; border-bottom: 1px dotted #d9c9b0; }
  .item b { font-weight: 700; }
  .item small { display: block; font: 14px/1.35 system-ui, sans-serif; color: #7a6a58; }
  .price { font: 600 16px system-ui, sans-serif; white-space: nowrap; font-variant-numeric: tabular-nums; }
  .tag { font: 600 11px system-ui, sans-serif; background: #e7efe0; color: #3b5a2a; border-radius: 4px; padding: 1px 6px; margin-left: 4px; }
  .out { opacity: .5; }
  .out .price { text-decoration: line-through; }
  footer { text-align: center; font: 13px system-ui, sans-serif; color: #7a6a58; padding: 0 20px 28px; }
</style>
</head>
<body>
<header>
  <h1>Juniper Lane Cafe</h1>
  <p>Open daily 7:30 - 16:00 &middot; Prices in dollars</p>
</header>
<nav>
  <a href="#coffee">Coffee</a>
  <a href="#tea">Tea</a>
  <a href="#breakfast">Breakfast</a>
  <a href="#bakery">Bakery</a>
</nav>
<main>
  <section id="coffee">
    <h2>Coffee</h2>
    <div class="item"><div><b>Espresso</b></div><span class="price">3.00</span></div>
    <div class="item"><div><b>Flat white</b><small>Double shot, steamed milk</small></div><span class="price">4.50</span></div>
    <div class="item"><div><b>Latte</b> <span class="tag">oat milk +0.60</span></div><span class="price">4.80</span></div>
    <div class="item out"><div><b>Cold brew</b><small>Sold out today</small></div><span class="price">4.20</span></div>
  </section>
  <section id="tea">
    <h2>Tea</h2>
    <div class="item"><div><b>Pot of black tea</b></div><span class="price">3.80</span></div>
    <div class="item"><div><b>Mint and ginger infusion</b></div><span class="price">3.80</span></div>
  </section>
  <section id="breakfast">
    <h2>Breakfast</h2>
    <div class="item"><div><b>Eggs on toast</b><small>Two eggs, sourdough</small></div><span class="price">8.50</span></div>
    <div class="item"><div><b>Granola bowl</b> <span class="tag">vegan</span><small>Oat granola, seasonal fruit</small></div><span class="price">7.20</span></div>
  </section>
  <section id="bakery">
    <h2>Bakery</h2>
    <div class="item"><div><b>Butter croissant</b></div><span class="price">3.40</span></div>
    <div class="item"><div><b>Cardamom bun</b></div><span class="price">3.90</span></div>
  </section>
</main>
<footer>Please ask us about allergens before you order.</footer>
</body>
</html>
A finished cafe menu page with four sections, prices, a tag and a sold-out item. Scroll inside the frame.

Make it with AI

You do not write the HTML. Paste this into ChatGPT, Claude or Gemini, and replace the bracketed parts with your own details.

Write one self-contained HTML file for a cafe menu.
Cafe name: [name]. Hours: [hours]. Currency symbol: [symbol].
Sections and items (name, price, optional short note):
[paste your list here]
Rules:
- Works on a phone: viewport meta tag, large readable text.
- Sticky row of section buttons at the top that jump to each section.
- Name on the left, price on the right, on one line.
- No external images, fonts or scripts. No order form.
- Do not add items, prices or allergen claims I did not give you.
- Put all the text I gave you in the page exactly as written.

ChatGPT and other chat tools put code in a block you can copy, according to OpenAI's help page. Copy the whole block, from the first line to the last.

What to check in the result:

  • Every item and price matches your own list, one by one.
  • No items, hours or allergen notes you did not write.
  • The section buttons all jump to the right place.
  • It still looks right when you shrink the browser window narrow.

If something is off, tell the AI what to change in plain words. "Make the prices bold" works.

From your item list to a link on your profiles: ask, check, paste, post.
From your item list to a link on your profiles: ask, check, paste, post.

Open NOS, create a document, and paste the HTML. It shows as a finished page, and scripts on it run. Then choose Share and Create share link. HTML to link walks through it.

What the visitor sees: the menu opens in their browser, phone included. No account is needed, and they cannot edit it. If you change a price in the code later, the same link shows the new version.

A menu sent as a file compared with a menu sent as a link.
A menu sent as a file compared with a menu sent as a link.

You already have places that accept a link. Paste the same address into each one.

One menu address used in four places.
One menu address used in four places.
  • Instagram: the profile has a link or website field. Instagram's Help Center explains it on the page Add a website to your Instagram profile. Steps can change, so check it as of October 2026.
  • Google Business Profile: go to Edit profile, then Business information, then Contact, then Menu link. Google says this is available to food and drink businesses, and updates can take 24 to 48 hours.
  • Facebook Page: open About, then the contact and basic info section. Which fields appear depends on your Page category.
  • Table or window: a QR code can hold the same address. See QR code link.

Whatever you paste, test it on your own phone first.

What a cafe menu page needs

A good menu page is short and plain. Visitors may open it on a phone, so the page should show prices in a readable column without zooming.

  • Section buttons at the top: Coffee, Tea, Breakfast, Bakery. One tap jumps to the section.
  • One line per item: the name on the left, the price on the right.
  • A short note only when it helps: "Double shot, steamed milk."
  • A sold-out state: grey the line out and keep it visible.
  • Hours and a request to ask about allergens: keep this to one line each.

For why a menu works better as a page than as a file, see How to put a menu at a link and how to make an online menu.

Ways to share a menu, compared

Way What the visitor does Changing a price Fits a link field
Photo of the printed menu Reads an image Retake and repost No, it is an image
File attachment Downloads, opens in an app Send a new file No, it wants an address
Menu page as a link Taps, reads in the browser Edit the page, same link Yes

The link is also the only one of the three you can keep identical on every profile.

Keep it current: a menu you edit in one place

Prices, specials and sold-out items change. This second example keeps all the items in one list at the top of the code. Change a number or add soldOut: true, and the page redraws. Try the filters.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Juniper Lane Cafe - Menu board</title>
<style>
  * { box-sizing: border-box; }
  body { margin: 0; font-family: system-ui, sans-serif; background: #f3f1ec; color: #232323; line-height: 1.45; }
  .wrap { max-width: 560px; margin: 0 auto; padding: 22px 18px 40px; }
  h1 { margin: 0 0 2px; font-size: 24px; }
  .sub { margin: 0 0 14px; color: #6b665d; font-size: 14px; }
  .special { background: #fff3d6; border: 1px solid #ecd699; border-radius: 12px; padding: 12px 14px; margin-bottom: 16px; }
  .special b { display: block; font-size: 13px; letter-spacing: .6px; text-transform: uppercase; color: #8a5a00; }
  .filters { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 8px; }
  .filters button { font: 600 14px system-ui, sans-serif; padding: 8px 14px; border-radius: 999px; border: 1px solid #cfc9bd; background: #fff; color: #333; cursor: pointer; }
  .filters button[aria-pressed="true"] { background: #2f5d3a; border-color: #2f5d3a; color: #fff; }
  h2 { font-size: 16px; margin: 20px 0 4px; color: #2f5d3a; }
  .row { display: flex; justify-content: space-between; gap: 14px; padding: 10px 0; border-bottom: 1px solid #e3dfd6; }
  .row small { display: block; color: #6b665d; font-size: 13px; }
  .row .p { font-weight: 700; white-space: nowrap; font-variant-numeric: tabular-nums; }
  .row.out { opacity: .5; }
  .row.out .p { text-decoration: line-through; }
  .empty { color: #6b665d; font-size: 14px; padding: 10px 0; }
</style>
</head>
<body>
<div class="wrap">
  <h1>Juniper Lane Cafe</h1>
  <p class="sub">Tap a filter. Edit the list in the script to change the menu.</p>
  <div class="special"><b>Today's special</b><span id="special"></span></div>
  <div class="filters" id="filters"></div>
  <div id="menu"></div>
</div>

<script>
  // 1. Edit only this part: your name, special, and items
  const SPECIAL = 'Pumpkin spice latte, 5.20';
  const ITEMS = [
    { section: 'Coffee',    name: 'Flat white',      price: 4.50, note: 'Double shot, steamed milk' },
    { section: 'Coffee',    name: 'Oat latte',       price: 5.00, tags: ['vegan'] },
    { section: 'Coffee',    name: 'Cold brew',       price: 4.20, soldOut: true },
    { section: 'Breakfast', name: 'Granola bowl',    price: 7.20, tags: ['vegan'], note: 'Oat granola, seasonal fruit' },
    { section: 'Breakfast', name: 'Cheese toastie',  price: 6.80, tags: ['vegetarian'] },
    { section: 'Bakery',    name: 'Butter croissant', price: 3.40, tags: ['vegetarian'] },
    { section: 'Bakery',    name: 'Almond cookie',   price: 2.90, tags: ['vegan'] }
  ];
  const FILTERS = ['all', 'vegan', 'vegetarian'];

  // 2. The rest builds the page from the list
  let current = 'all';
  document.getElementById('special').textContent = SPECIAL;

  function draw() {
    const box = document.getElementById('menu');
    box.innerHTML = '';
    const shown = ITEMS.filter(i => current === 'all' || (i.tags || []).includes(current));
    if (!shown.length) { box.innerHTML = '<p class="empty">Nothing here today.</p>'; return; }
    [...new Set(shown.map(i => i.section))].forEach(sec => {
      const h = document.createElement('h2');
      h.textContent = sec;
      box.appendChild(h);
      shown.filter(i => i.section === sec).forEach(i => {
        const row = document.createElement('div');
        row.className = 'row' + (i.soldOut ? ' out' : '');
        const left = document.createElement('div');
        const name = document.createElement('span');
        name.textContent = i.name + (i.soldOut ? ' (sold out)' : '');
        left.appendChild(name);
        if (i.note) { const s = document.createElement('small'); s.textContent = i.note; left.appendChild(s); }
        const p = document.createElement('span');
        p.className = 'p';
        p.textContent = i.price.toFixed(2);
        row.append(left, p);
        box.appendChild(row);
      });
    });
  }

  const bar = document.getElementById('filters');
  FILTERS.forEach(f => {
    const b = document.createElement('button');
    b.textContent = f === 'all' ? 'All' : f[0].toUpperCase() + f.slice(1);
    b.setAttribute('aria-pressed', f === current);
    b.addEventListener('click', () => {
      current = f;
      bar.querySelectorAll('button').forEach(x => x.setAttribute('aria-pressed', x === b));
      draw();
    });
    bar.appendChild(b);
  });
  draw();
</script>
</body>
</html>
The same menu built from one list. Filter by vegan or vegetarian, and see the sold-out line.

Ask your AI for this version if you change the menu often: "Keep all items in one JavaScript list at the top so I can edit prices easily." Then you only touch that list.

For specials, a one-line banner at the top is enough. Edit it each morning and delete it when it is over. If you also use printed menus, price list link covers keeping a price list current.

When it does not work

Symptom Cause Fix
Menu shows as code, not a page You pasted the AI's explanation too, or only part of the block Copy the whole code block and paste only that
Section buttons do nothing The AI built them without matching section names Ask it to make each button jump to its section
Text is tiny on a phone The viewport meta tag is missing Ask the AI to add the viewport meta tag
A photo or logo is missing Pictures from other sites are blocked on shared pages Ask for a drawn logo or text only
Order button does not send Forms cannot send to a server from the shared page Use the page for reading, and take orders as before
Google still shows the old link Updates can take 24 to 48 hours Wait, then check again
Cannot find the Instagram link field Where it sits can change with the app version Follow the steps on Instagram's help page

Questions people ask

Is there a free cafe menu template I can copy?

The first example on this page is a complete menu you can copy. Paste it into an AI chat and ask it to swap in your cafe name, items and prices, or ask the AI to write one from scratch with the prompt below.

Can I put the menu link in my Instagram bio?

Yes, if your profile has a link or website field. Instagram has a Help Center page called Add a website to your Instagram profile, and the steps can change with the app version, so check it as of October 2026.

Where does a menu link go on Google?

In your Google Business Profile: Edit profile, Business information, Contact, Menu link. Google says this is available to food and drink businesses, and changes can take 24 to 48 hours to appear on Google Maps and Search.

Do I have to change the link when a price changes?

No. Edit the code in your NOS document and the same link shows the new version. Your profiles keep the address they already have.

Can customers order from this page?

It shows the menu. A form that sends orders to a server is blocked on shared pages, so use the page for reading the menu and keep taking orders the way you do now.

Keep reading