Restaurant online ordering everyone can use: menu items, options, cart and pickup times
How to make a restaurant, cafe, bakery or caterer's online ordering page accessible: named Add buttons, announced required options, item pop-ups that handle focus, a cart that says when it changes, keyboard-friendly pickup times and tips, with copyable code and a 5-minute check.
Online ordering is where a restaurant, cafe, bakery or caterer actually takes money, and it gets busy in November and December with Thanksgiving pie pre-orders, holiday platters and office lunch orders. A typical ordering page has a menu list, an item pop-up with sizes and add-ons, a cart, a pickup or delivery time, a tip and payment. Each step can stop a customer who uses a screen reader, a keyboard, voice control or a magnifier: a "+" button with no name, a required "choose a side" that only shows up in red, an item pop-up you can't close with the keyboard, a pickup time picker that only works with a mouse, or a cart total that changes without saying so. Recent online talk about menus has also been about photos that don't match the food. Real photos with short, honest alt text help everyone.
1. Menu items and "Add" buttons with real names
A long list of "+" or "Add" buttons all sound the same to a screen reader. Give each one a name that includes the dish (4.1.2 Name, Role, Value, 2.4.4 Link Purpose (In Context)), keep the price and dietary info as text next to the dish name, and use headings for menu sections so people can jump between "Starters", "Mains" and "Desserts" (1.3.1 Info and Relationships). Make every tap target at least 24 by 24 pixels, and ideally 44 (2.5.8 Target Size (Minimum)).
<h2 id="mains">Mains</h2>
<ul class="menu">
<li>
<h3 id="dish-12">Chicken pot pie</h3>
<p>Flaky crust, roast chicken, peas and carrots. <span class="tag">Contains dairy, wheat</span></p>
<p class="price">$14.50</p>
<button type="button" aria-describedby="dish-12">Add<span class="sr-only"> chicken pot pie</span></button>
</li>
</ul>
<!-- example dish and price; use your real menu -->
The dish, allergens and price above are example values. Don't use icons alone for "vegan" or "spicy"; add a word or a text label (1.4.1 Use of Color, 1.1.1 Non-text Content). For photos, write alt text that describes what's on the plate, such as "Chicken pot pie with a golden lattice crust", and leave it out of the photo if it's purely decorative. See alt text examples.
2. Item options and required choices that are announced
Sizes, sides and add-ons are choices, so build them as fieldsets with a legend. Use radio buttons when only one is allowed and checkboxes when several are, and say in the legend text when a choice is required or limited (3.3.2 Labels or Instructions). If someone presses "Add to order" without a required choice, move focus to it and say what's missing in words, not just with a red outline (3.3.1 Error Identification).
<fieldset aria-describedby="side-error"> <legend>Choose a side (required, pick 1)</legend> <label><input type="radio" name="side" value="salad" required> Side salad</label> <label><input type="radio" name="side" value="fries"> Fries (+$1.00)</label> <p id="side-error" class="error" hidden>Choose a side to add this to your order.</p> </fieldset> <fieldset> <legend>Extras (optional, pick up to 3)</legend> <label><input type="checkbox" name="extra" value="gravy"> Extra gravy (+$0.75)</label> <label><input type="checkbox" name="extra" value="cheese"> Cheddar on top (+$1.00)</label> </fieldset> <label for="notes">Special instructions (optional)</label> <p id="notes-hint" class="hint">Tell us about allergies here. We'll do our best, but can't promise a nut-free kitchen.</p> <textarea id="notes" name="notes" rows="3" aria-describedby="notes-hint"></textarea> <!-- example options, prices and allergy wording; use your own -->
The options, prices and allergy wording above are examples; use your kitchen's real policy. See form error messages.
3. An item pop-up that behaves like a real dialog
Many ordering systems open each dish in a pop-up. It needs a name, focus should move into it when it opens, Escape and a labelled Close button should shut it, and focus should return to the dish you opened it from (2.4.3 Focus Order, 2.1.2 No Keyboard Trap). The native dialog element does most of this for you.
<dialog id="item-dialog" aria-labelledby="item-title">
<h2 id="item-title">Chicken pot pie</h2>
<form method="dialog">
<!-- options from section 2 go here -->
<button value="add">Add to order, $14.50</button>
<button value="cancel" formnovalidate>Close</button>
</form>
</dialog>
<script>
let opener;
function openItem(btn) {
opener = btn;
document.getElementById('item-dialog').showModal(); // moves focus in, Escape closes
}
document.getElementById('item-dialog').addEventListener('close', () => opener && opener.focus());
</script>
A "sticky" cart bar or chat button should never cover the focused field or button (2.4.11 Focus Not Obscured (Minimum)). See pop-ups and chat widgets.
4. A cart that says when it changes
When someone adds an item, the cart count or total often updates in a corner they can't see. Announce it briefly with a status message (4.1.3 Status Messages), and let people change quantities or remove items with labelled buttons, such as "Remove chicken pot pie" rather than an unnamed bin icon.
<p id="cart-status" class="sr-only" role="status"></p>
<script>
function announceCart(name, count, total) {
document.getElementById('cart-status').textContent =
name + ' added. ' + count + ' items in your order, total ' + total + '.';
}
// announceCart('Chicken pot pie', 2, '$29.00'); // example values
</script>
5. Pickup or delivery time, tip and review
A pickup time is a short list of slots, so a native select or a radio group works with every keyboard and screen reader, unlike a custom scrolling picker (2.1.1 Keyboard). Say in words when the kitchen is closed or a slot is full instead of greying it out. For tips, use a labelled radio group with a custom amount field, and don't pre-select a high tip in a way people can miss. Before payment, show the items, options, time, tip and total as text with "Edit" links (3.3.4 Error Prevention (Legal, Financial, Data)), and let the browser fill in name, phone and email (1.3.5 Identify Input Purpose). If the cart has a time limit, warn people; see countdowns and time limits.
<label for="pickup">Pickup time</label> <p id="pickup-hint" class="hint">Orders take about 20 minutes. Full times aren't listed.</p> <select id="pickup" name="pickup" aria-describedby="pickup-hint" required> <option value="">Choose a time</option> <option>Today, 5:30 PM</option> <option>Today, 5:45 PM</option> <option>Today, 6:15 PM</option> </select> <!-- example times and prep time; use your real ones -->
The times above are examples. After the order goes through, show a confirmation page with a clear heading, the order number and pickup time as text, and send the same in the email or text message. See online store checkout for payment steps.
Platform notes
- Toast, Square Online, Clover, ChowNow, Owner.com and similar: the ordering page is usually hosted by the provider, so you control the menu text, photos, alt text, item names, option names and wording, but not most of the code. Test it with a keyboard anyway and send the provider specific problems; ask whether they have a current accessibility conformance report. See conformance reports.
- Shopify: pre-orders and pickup often come from apps; check the app's product options and date or time picker. See Shopify fixes.
- WordPress and WooCommerce: food ordering plugins vary widely; check the item pop-up, required options and the cart update. See WordPress fixes.
- Squarespace, Wix, GoDaddy and Webflow: built-in commerce or embedded ordering widgets; check option labels and errors. See Squarespace, Wix, GoDaddy and Webflow.
- AI-built sites: check that generated "Add" buttons are real buttons with names and that pop-ups trap and return focus correctly. See checking an AI-built site.
Settings and app names change often, so check your platform's or provider's own help pages for the current option.
Common mistakes
- Dozens of "+" or "Add" buttons with no dish name.
- Menus posted only as a photo or PDF, with no text version. See menus and PDFs.
- Required choices shown only with red or a star, and no message when they're skipped.
- Item pop-ups that can't be closed with Escape or that drop focus at the top of the page.
- A cart total that changes silently.
- A mouse-only pickup time picker, or full slots shown only as grey.
- Allergen and diet info only as icons.
- Photos with alt text like "IMG_2041" or that don't match the real dish.
A 5-minute check you can do today
- Open your ordering page and press Tab. Does every "Add" button say which dish it adds? See our keyboard test.
- Open a dish with options and try to add it without picking a required one. Is the message in words, and does focus go to it?
- Press Escape in the item pop-up. Does it close and put you back on the dish?
- Pick a pickup time and a tip using only the keyboard.
- Zoom to 200%. Does the cart bar cover the button you're on? See zoom and tap targets.
What a scan can and can't check here
Our scan is automated, so it finds only part of the barriers on the pages it visits, and many ordering pages are hosted by a provider on a separate address. On your own pages it can flag buttons and links with no name, form fields with no label, images with no alt attribute, low contrast and missing page titles. It can't tell whether a pop-up handles focus properly, whether required choices are announced, whether the cart update is spoken, or whether your photos match the food, which is why the 5-minute check above matters. Our Fix-Pack reports include copy-paste fixes for what we find on your site and say plainly what needs a person to check.
Related: restaurant websites, caterers, food trucks and meal prep, bakeries and gift shops, gift card pages, WCAG 2.2 explained.
This is general technical guidance, not legal advice, and it doesn't certify compliance with the ADA or any law, or protect against claims.
Want the fixes written for you?
Start with a free homepage snapshot. The $149 Fix-Pack scans up to 10 pages and gives copy-paste fixes for your platform within 48 hours, with a 14-day refund promise. See a sample report first.
This is general technical guidance, not legal advice, and it does not certify compliance with the ADA or any law.
Using Square Online? See Square Online accessibility fixes.
Using QR codes on tables, flyers or signs? See QR codes and QR code menus.
Related guides
- Client website handoff: an accessibility checklist and dated record for web designers
- 404, error and maintenance pages that don't strand visitors: an accessibility guide
- Vacation rental direct booking pages: accessible calendars, dates, guests and prices
- Interactive portfolio sites: accessible 3D scenes, games, custom cursors and scroll effects
This guide is general technical information, not legal advice. Following it does not certify ADA or any legal compliance. Automated checks find only part of accessibility barriers.
Check your own site, then decide
- Free homepage snapshot. Your top 3 issues in about a minute. No signup, no card.
- $149 Fix-Pack, if you want the full list. Up to 10 pages scanned, issues ranked by impact, copy-paste fixes for your platform, delivered within 48 hours, plus one re-scan after you apply them.
Get my free snapshot Order the Fix-Pack – $149
14-day refund promise. See a sample report first. A technical report, not legal advice; automated checks find only part of accessibility barriers.