Skip to content

Search

The global and local search components each include

Version:
0.1.0
Status:
Published

Introduction

GEL documents global and local search separately. However, for the sake of consistency, each mode of search is implemented as a similar visual, semantic, and interactive pattern.

This Page does not document search results or filtering. Choosing a suggestion based on a search term takes the user directly to the suggested permalink, whereas pressing the submit button will take the user to the www.bbc.co.uk/search page to browse and filter results.

Whether local or global, the search component must be marked up as a role="search" landmark, making it available to screen reader shortcuts. The role="search" attribution must not be placed on the form, but instead on a wrapping element[1]. ARIA roles suppress implicit roles, and remove their associated behaviors. Screen readers should still be able to identify the form as a form.

<div class="gel-search" role="search">
  <form class="gel-search-controls">
    <!-- search functionality here -->
  </form>
</div>

The search component is composed of two main parts: the search controls (class="gel-search-controls"), and the associated search suggestions (class="gel-search-suggestions").

Search controls

The following example is for a global search region. It would be revealed by pressing the search button in the page's Masthead, and includes a close button to dismiss it again. SVG data is elided. There are notes to follow.

<form class="gel-search-controls" method="get" action="https://search.bbc.co.uk/search">
  <label for="search" hidden>Search the BBC</label>
  <input type="text" id="search" name="search" />
  <button type="submit">
    <span class="gel-sr">Search</span>
    <svg class="gel-icon gel-icon--text" focusable="false">
      ...
    </svg>
  </button>
  <button type="button" class="gel-search-close">
    <span class="gel-sr">Close</span>
    <svg class="gel-icon gel-icon--text" focusable="false">
      ...
    </svg>
  </button>
</form>
  • "Search the BBC": Because this is a global search region, the label for the search input simply reads "Search the BBC". This text is hidden but associated with the input, and available to screen readers, by making the <label>'s for attribute and the input's id share a value.
  • Buttons: Each button uses the native button element. The close button takes type="button" to differentiate it from a submit button and prevent it from erroneously submitting the form[2].
  • SVG: Each SVG must take focusable="false" and aria-hidden="true" to ensure it is unavailable to assistive technologies and not focusable by keyboard.

A local search region differs in three ways:

  • A logo is included for branding purposes.
  • The input label reads "Search BBC [site name]" (a non-visual equivalent of the logo).
  • The close button is omitted, since local search is a permanent fixture placed under the masthead.
  • A placeholder may be included, but not as a replacement for the <label> which must remain intact. As GEL's local search documentation recommends, the placeholder should contain search suggestions, for example "enter a town, city, or postcode"

See the local search reference implementation.

Search suggestions

Where available, typing into the search input populates a region below the search controls with suggested links. This region looks like the following in its initial state (with notes to follow):

<aside class="gel-search-suggestions" aria-label="Search suggestions" aria-hidden="true" hidden>
  <h2 class="gel-search-suggestions-label" role="status" aria-live="polite"></h2>
  <div class="gel-search-suggestions-links"></div>
</aside>
  • <aside>: The suggestions region is provided as a complementary landmark. This makes it easy to locate using screen reader software (while it is available) and allows for the descriptive label: "Search suggestions". When a screen reader user enters the region and focuses a suggestion link they will hear something similar to, "search suggestions, complementary region, list of 5 items, first item, [item text], link" (where 5 suggestions are available and presented in a list — which is recommended).
  • aria-hidden="true" and hidden: In the initial state, the region is not visible, on account of having zero height and overflow: hidden (see the Recommended layout section. To achieve parity for screen reader users, aria-hidden="true" 'hides' the region from their software. The hidden property hides the region unless JavaScript (upon which it depends) runs and can remove it.
  • role="status": When suggestions become available, screen reader users should be informed — and without stealing their focus. A live region is populated with text following the template "We have [n] suggestions for you<span class="gel-sr">, please find them below</span>:". The "please find them below" portion is only helpful non-visually, so is visually hidden using the .gel-sr class. The aria-live="polite" attribution is equivalent to role="status". Some browsers only support one of the two attributes, so this maximizes compatibility.
  • .gel-search-suggestions-links: A function provided by the developer would be used to populate lists of suggestions (see the Reference implementations)

The search region itself uses Flexbox to bring its items inline. The input is allowed to grow and shrink, helping the component support a range of viewport widths.

.gel-search-controls {
  display: flex;
  align-items: center;
}

.gel-search-controls > input {
  flex-grow: 1;
  min-width: 0;
}

Focus styles

Strong—not just default—focus styles are recommended. In the Reference implementations, a solid outline is employed, with a negative outline-offset to bring the outline inside the input and button boxes:

.gel-search-controls > input:focus,
.gel-search-controls > button:focus {
  outline: 2px solid;
  outline-offset: -2px;
}

Here is the basic workflow for using search, with actions/behaviours specific to global search marked as such:

  1. Click the search button in the Masthead → the search region is revealed and the search input is focused. (global search only)
  2. Type inside the search field → If suggestions are available, they populate the suggestions region, and it is revealed. For screen reader users, the presence of suggestions (and the number available) is announced via the live region.
  3. Click on the submit button → The user is taken to the search page (https://search.bbc.co.uk/search)
  4. Click on a suggestion → The user is taken to that suggestion's permalink
  5. Click on the close ('X') button → the search region is hidden and the Masthead's search button regains keyboard focus (global search only)

The Reference implementation includes a toggle method for assigning and enhancing an element intended for opening and focusing the search component. In the global search demo, this element is the 'Search' link in the Masthead.

Where JavaScript does not run, this link is followed and the search page opened (in the same tab). Where JavaScript does run, the link is enhanced into a popup button (taking role="button" and aria-haspopup="true"). The event.preventDefault() method is applied, and the newly coined button launches the search component described in this page instead.

When the user presses the close button to the right of the search input's submit button, focus is returned to the invoking popup button, as described in (5), above.

Animating the suggestions region

The animation (sliding up and down) of the suggestions region uses JavaScript, not just CSS. This is because you cannot animate to an auto height, and the height of the region—including the dynamic suggestions content—cannot be known ahead of time. Instead, the scrollHeight of the region must be determined and that height made the 'target' for the animation end. Importantly, the function that populates the suggestions must be executed before the animation function. Otherwise the target height will be incorrect.

Here is the entire process:

// Use the supplied function to populate the suggestions
buildFunction(this);
// Set `aria-hidden` to `false` so:
// (a) the live region will announce
// (b) the suggestions will be available to screen readers
this.suggestions.setAttribute('aria-hidden', 'false');
// Now safely populate the live region
this.suggestionsLabel.innerHTML = 'We have <span class="search-suggestion-count">' + this.suggestionsLinks.querySelector('a').length + '</span> suggestions for you<span class="gel-sr">, please find them below</span>:'
// Finally, animate the region into view
this.showSuggestions();

Reference implementation

Open in new window

The global search implementation uses the Masthead component, and must be opened in a new window.

Open in new window

This topic does not yet have any related research available.

Further reading, elsewhere on the Web


  1. Where To Put Your Search Role — Adrian Roselli, http://adrianroselli.com/2015/08/where-to-put-your-search-role.html ↩︎

  2. Why it's important to give your HTML button a type — dev.to (Claire Parker), https://dev.to/claireparkerjones/why-its-important-to-give-your-html-button-a-type-58k9 ↩︎

  3. <datalist> — MDN, https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist ↩︎

  4. Combobox - ARIA Authoring Practices, https://www.w3.org/TR/wai-aria-practices/#combobox ↩︎

Copyright © 2021 BBC. This content is published under the Open Government Licence, unless otherwise noted.