Site search that everyone can use: search boxes, suggestions and results pages

How to make the search box, predictive search suggestions and search results on a small business website work with a keyboard, screen readers and phones: a labelled search form, copyable keyboard-friendly suggestion code, results and no-results pages, platform notes and a 5-minute check.

Holiday gift hunting is in full swing, and a lot of it starts with a search box. Shoppers type "host gift", "candle under $30" or "gift card" instead of clicking through menus, and people are building filterable lists and AI tools just to sort gift ideas. On a small business site, the search box is often the fastest way to a sale, and it matters even more for people who find menus hard: screen reader users, keyboard and switch users, people with memory or reading difficulties, and anyone on a small phone screen. Search is also one of the "more than one way to find a page" options WCAG asks for (2.4.5 Multiple Ways). Yet site search is often an unlabelled icon, a field with only placeholder text, a suggestion list the keyboard can't reach, and a results page that never says how many results it found. Here's how to fix each part.

1. The search box: a label, a named button and a search landmark

Wrap the form in role="search" (or the newer <search> element) so screen reader users can jump straight to it. Give the field a real label, visible if you have room or visually hidden if the design is tight, because placeholder text disappears as people type and isn't reliably read out (3.3.2 Labels or Instructions, 1.3.1 Info and Relationships). The button needs a name even if it only shows a magnifying glass (4.1.2 Name, Role, Value).

<form role="search" action="/search" method="get" class="site-search">
  <label for="site-search-q">Search products</label>
  <input id="site-search-q" name="q" type="search" enterkeyhint="search" autocomplete="off">
  <button type="submit">
    <svg aria-hidden="true" focusable="false" width="20" height="20" viewBox="0 0 24 24"><path d="M10 2a8 8 0 1 0 4.9 14.3l5.4 5.4 1.4-1.4-5.4-5.4A8 8 0 0 0 10 2zm0 2a6 6 0 1 1 0 12 6 6 0 0 1 0-12z"/></svg>
    <span class="visually-hidden">Search</span>
  </button>
</form>

<style>
  .site-search input { min-height: 44px; font-size: 1rem; border: 2px solid #555; padding: 0 .5rem; }
  .site-search button { min-width: 44px; min-height: 44px; }
  .site-search :focus-visible { outline: 3px solid #1a1a1a; outline-offset: 2px; }
  /* use this class only if the design truly has no room for a visible label */
  .visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
</style>
<!-- example action URL, field name and wording; use the ones your platform expects -->

The action URL, field name and wording above are example details. Most platforms already have a search URL (often /search with a q field); keep whatever yours uses. The field border is dark enough to see against white (1.4.11 Non-text Contrast), and the button is well over the 24 by 24 CSS pixel minimum (2.5.8 Target Size (Minimum)). A 16px (1rem) font size also stops iPhones zooming in when people tap the field.

2. "Search icon" buttons that open a field

Many themes hide the field behind a magnifying-glass icon in the header. That's fine if the icon is a real <button> with a name such as "Open search", it says whether the search is open with aria-expanded, pressing it moves the keyboard focus into the field, and Escape closes it and returns focus to the icon. If the search opens as a full-screen overlay, it must also be closable with a visible close button. See accessible links and buttons and focus indicators.

3. Search suggestions ("predictive search") that work with a keyboard

Suggestions that drop down as you type help everyone, but they're one of the hardest things to build accessibly. If your platform or theme provides predictive search, test it with the check below before writing your own. If you do build one, the W3C combobox pattern is the reference. The key parts: the field says the list is open, Up and Down arrows move through suggestions while focus stays in the field, Enter picks one, Escape closes the list, and the number of suggestions is announced without moving focus (4.1.3 Status Messages). Typing should never jump to a new page on its own (3.2.2 On Input).

<form role="search" action="/search" method="get">
  <label for="sq">Search products</label>
  <input id="sq" name="q" type="search" role="combobox" autocomplete="off"
         aria-autocomplete="list" aria-expanded="false" aria-controls="sq-list">
  <ul id="sq-list" role="listbox" aria-label="Suggestions" hidden></ul>
  <p id="sq-status" role="status" class="visually-hidden"></p>
  <button type="submit">Search</button>
</form>

<script>
  // example suggestions; load your real product or page names instead
  var ITEMS = ['Soy candle, cedar', 'Soy candle, vanilla', 'Gift card', 'Gift box, small', 'Host gift set'];
  var input = document.getElementById('sq'), list = document.getElementById('sq-list');
  var status = document.getElementById('sq-status'), active = -1;

  function close() { list.hidden = true; input.setAttribute('aria-expanded', 'false'); input.removeAttribute('aria-activedescendant'); active = -1; }
  function highlight(i) {
    var opts = list.querySelectorAll('[role=option]');
    opts.forEach(function (o, n) { o.setAttribute('aria-selected', n === i); });
    active = i;
    if (opts[i]) input.setAttribute('aria-activedescendant', opts[i].id);
  }
  function pick(text) { input.value = text; close(); }

  input.addEventListener('input', function () {
    var q = input.value.trim().toLowerCase();
    var hits = q ? ITEMS.filter(function (t) { return t.toLowerCase().indexOf(q) > -1; }).slice(0, 6) : [];
    list.innerHTML = '';
    hits.forEach(function (t, n) {
      var li = document.createElement('li');
      li.id = 'sq-opt-' + n; li.setAttribute('role', 'option'); li.setAttribute('aria-selected', 'false');
      li.textContent = t;
      li.addEventListener('click', function () { pick(t); input.focus(); });
      list.appendChild(li);
    });
    if (hits.length) { list.hidden = false; input.setAttribute('aria-expanded', 'true'); } else { close(); }
    status.textContent = q ? hits.length + (hits.length === 1 ? ' suggestion' : ' suggestions') + ' available' : '';
  });

  input.addEventListener('keydown', function (e) {
    var count = list.querySelectorAll('[role=option]').length;
    if (e.key === 'ArrowDown' && count) { e.preventDefault(); list.hidden = false; input.setAttribute('aria-expanded', 'true'); highlight((active + 1) % count); }
    else if (e.key === 'ArrowUp' && count) { e.preventDefault(); highlight((active - 1 + count) % count); }
    else if (e.key === 'Enter' && active > -1 && !list.hidden) { e.preventDefault(); pick(list.querySelectorAll('[role=option]')[active].textContent); }
    else if (e.key === 'Escape') { close(); }
  });
  input.addEventListener('blur', function () { setTimeout(close, 150); });
</script>

<style>
  #sq-list { list-style: none; margin: 0; padding: 0; border: 1px solid #555; max-width: 24rem; }
  #sq-list [role=option] { padding: .5rem .75rem; min-height: 24px; cursor: pointer; }
  #sq-list [aria-selected=true] { background: #1a1a1a; color: #fff; outline: 2px solid #1a1a1a; }
</style>
<!-- example items and wording; use your real product names -->

The suggestion items above are example data. Picking a suggestion fills the field and the person then presses Search, so nothing jumps away mid-typing. The highlighted suggestion changes both colour and outline, so it isn't shown by colour alone. Test any custom version with a real screen reader before you rely on it.

4. The results page: say what was found

After a search, people need to know straight away whether it worked. Put the search term and the number of results in the page title and the main heading (2.4.2 Page Titled), keep the search box filled in with what they typed so they can adjust it, and give each result a heading or a clear link name. If filters or sorting update the results without reloading the page, announce the new count in a status message and don't move focus.

<title>Search results for "candle" (3) | Example Candle Co.</title>

<main id="main">
  <h1>3 results for "candle"</h1>
  <p role="status">Showing 3 results. Sorted by best match.</p>
  <ul class="results">
    <li><h2><a href="/products/soy-candle-cedar">Soy candle, cedar, 8 oz</a></h2><p>$24.00. In stock.</p></li>
    <li><h2><a href="/products/soy-candle-vanilla">Soy candle, vanilla, 8 oz</a></h2><p>$24.00. Low stock: 2 left.</p></li>
    <li><h2><a href="/products/host-gift-set">Host gift set with candle</a></h2><p>$38.00. In stock.</p></li>
  </ul>
</main>
<!-- example store name, products and prices; use your real ones and escape the search term -->

The store name, products and prices above are example data. Always escape the search term before you show it on the page, so a typed <script> can't run. Avoid infinite scroll on results: it can make the footer, contact details and filters impossible to reach. A "Show more results" button with the new count announced is easier for everyone.

5. "No results" should still help

A blank page or a lone "0 results" is where many shoppers leave. Say plainly that nothing matched, show the search box again with their term, suggest a spelling or a broader word, link your main categories or best sellers, and give a phone number or contact link ("Can't find it? Call us at ..."). If you can, add common misspellings and synonyms ("tee" for "t-shirt", "gift certificate" for "gift card") in your search settings. People with dyslexia, people using voice typing and anyone on a phone keyboard benefit most.

Platform notes

Settings and app names change often, so check your platform's or app's own help pages for the current option.

Common mistakes

A 5-minute check you can do today

  1. Load your home page and press Tab until you reach search. Can you get there, see where you are, and does the search icon or field have a clear name? See our keyboard test.
  2. Type a product or service name. If suggestions appear, use the Down arrow, Enter and Escape. Do they work without a mouse?
  3. Run the search. Does the page title and main heading say what you searched for and how many results there are?
  4. Search for something you don't sell, and for a misspelling of something you do. Does the page still help?
  5. On your phone, tap the search field. Is it big enough, does the keyboard show a search key, and is the text readable without zooming?
  6. With a screen reader (VoiceOver or NVDA), open the landmarks list. Is there a "search" landmark? See our screen reader test.

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. It can flag search fields with no label, icon buttons with no name, some ARIA mistakes in suggestion lists and low contrast. It doesn't type into your search box, so it can't tell whether suggestions work with the keyboard, whether results are announced, or whether your "no results" page helps, which is why the 5-minute check above matters. Our Fix-Pack reports include copy-paste fixes for your platform for what the scan finds.

Related: navigation menus and drop-downs, online store checkout, price filters and sliders, accessible contact forms, 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.

Selling from a product grid or collection page? See product grids, Load more, quick view and add to cart.

Don’t forget the page people see when a link is broken or your site is down: see accessible 404, error and maintenance pages.

Related guides

All guides

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

  1. Free homepage snapshot. Your top 3 issues in about a minute. No signup, no card.
  2. $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.