Soracom

Design System
  1. Home
  2. Design system
  3. Elements
  4. Autocomplete

Autocomplete

A container for an input and menu used as an autocomplete/type-ahead for the input.

This component requires Javascript for certain functionality, and implementing W3C WAI-ARIA accessibility recommendations

Overview

The autocomplete component is a container for a ds-input and __list used as the menu. This component only provides styling and does not provide any javascript required to implement auto-complete functionality.

Options

Basic usage

Non ARIA version

The following structure uses html hover and focus states to hide/reveal the list menu

Basic usage

html
Copy
<div class="ds-autocomplete">
  <div class="ds-input">
    <input type="text" name="test-field" />
  </div>
  <ul class="__list">
    <li>Anorith</li>
    <li>Arbok</li>
    <li>Arcanine</li>
    <li>Bulbasaur</li>
    <li>Butterfree</li>
    <li>Caterpie</li>
    <li>Charizard</li>
    <li>Charmander</li>
    <li>Charmeleon</li>
    <li>Squirtle</li>
    <li>Venusaur</li>
    <li>Wartortle</li>
  </ul>
</div>
  • Anorith
  • Arbok
  • Arcanine
  • Bulbasaur
  • Butterfree
  • Caterpie
  • Charizard
  • Charmander
  • Charmeleon
  • Squirtle
  • Venusaur
  • Wartortle

With ARIA attributes

The following structure uses role="combobox" and aria-expanded to hide/reveal the list menu. hover and focus will be ignored.

To show the list menu, set aria-expanded="true", to hide the list menu, set aria-expanded="false", aria-expanded="" or aria-expanded.

Basic usage

html
Copy
<!-- Click links to toggle aria-expanded state -->
<div class="ds-cols">
  <a
    href="#"
    onClick="document.getElementById('example-combobox').setAttribute('aria-expanded', true); return false;"
    ><code>aria-expanded="true"</code></a
  >
  <a
    href="#"
    onClick="document.getElementById('example-combobox').setAttribute('aria-expanded', false); return false;"
    ><code>aria-expanded="false"</code></a
  >
</div>

<!-- Autocomplete menu -->
<div class="ds-autocomplete">
  <div
    class="ds-input"
    id="example-combobox"
    role="combobox"
    aria-autocomplete="list"
    aria-controls="example-listbox"
    aria-expanded="false"
    aria-activedescendant=""
  >
    <input type="text" aria-label="Enter a Pokemon name" autocomplete="off" />
  </div>
  <ul class="__list" id="example-listbox" role="listbox">
    <li role="option">Anorith</li>
    <li role="option">Arbok</li>
    <li role="option">Arcanine</li>
    <li role="option">Bulbasaur</li>
    <li role="option">Butterfree</li>
    <li role="option">Caterpie</li>
    <li role="option">Charizard</li>
    <li role="option">Charmander</li>
    <li role="option">Charmeleon</li>
    <li role="option">Squirtle</li>
    <li role="option">Venusaur</li>
    <li role="option">Wartortle</li>
  </ul>
</div>
  • Anorith
  • Arbok
  • Arcanine
  • Bulbasaur
  • Butterfree
  • Caterpie
  • Charizard
  • Charmander
  • Charmeleon
  • Squirtle
  • Venusaur
  • Wartortle

Alternate usage with simple ds-input and ds-button

html
Copy
<!-- Click links to toggle aria-expanded state -->
<div class="ds-cols">
  <a
    href="#"
    onClick="document.getElementById('example-combobox-2').setAttribute('aria-expanded', true); return false;"
    ><code>aria-expanded="true"</code></a
  >
  <a
    href="#"
    onClick="document.getElementById('example-combobox-2').setAttribute('aria-expanded', false); return false;"
    ><code>aria-expanded="false"</code></a
  >
</div>

<!-- Autocomplete menu -->
<div class="ds-autocomplete">
  <input
    type="text"
    aria-label="Enter a Pokemon name"
    autocomplete="off"
    class="ds-input"
    id="example-combobox-2"
    role="combobox"
    aria-autocomplete="list"
    aria-controls="example-listbox"
    aria-expanded="false"
    aria-activedescendant=""
  />
  <button class="ds-button --plain --addon --icon-ui-arrow-down"></button>
  <ul class="__list" id="example-listbox" role="listbox">
    <li role="option">Anorith</li>
    <li role="option">Arbok</li>
    <li role="option">Arcanine</li>
    <li role="option">Bulbasaur</li>
    <li role="option">Butterfree</li>
    <li role="option">Caterpie</li>
    <li role="option">Charizard</li>
    <li role="option">Charmander</li>
    <li role="option">Charmeleon</li>
    <li role="option">Squirtle</li>
    <li role="option">Venusaur</li>
    <li role="option">Wartortle</li>
  </ul>
</div>
  • Anorith
  • Arbok
  • Arcanine
  • Bulbasaur
  • Butterfree
  • Caterpie
  • Charizard
  • Charmander
  • Charmeleon
  • Squirtle
  • Venusaur
  • Wartortle

Height

By default the autocomplete will be the height of the menu contents. You can also restrict the overall height of the menu and cause the contents to scroll. If the menu can scroll, a shadow will be added at the bottom/top of the menu to indicate the menu is scrollable.

There are two ways to restrict the height.

Restrict the height to the viewport

Adding the class --viewport to the menu will restrict the height to 100vh - --ds-header-height (usually 100vh - 60px) and force the menu to scroll.

Using viewport height - if the browser height is less than the menu height, the menu will scroll

html
Copy
<div class="ds-autocomplete">
  <div class="ds-input">
    <input type="text" name="test-field" />
  </div>
  <ul class="__list --viewport">
    <li>Anorith</li>
    <li>Arbok</li>
    <li>Arcanine</li>
    <li>Bulbasaur</li>
    <li>Butterfree</li>
    <li>Caterpie</li>
    <li>Charizard</li>
    <li>Charmander</li>
    <li>Charmeleon</li>
    <li>Squirtle</li>
    <li>Venusaur</li>
    <li>Wartortle</li>
  </ul>
</div>
  • Anorith
  • Arbok
  • Arcanine
  • Bulbasaur
  • Butterfree
  • Caterpie
  • Charizard
  • Charmander
  • Charmeleon
  • Squirtle
  • Venusaur
  • Wartortle

Restrict the height to a specific size

You can restrict the height by changing the --ds-menu-height value (either in a css file, inline style tag or via javascript).

let myCustomMenu = document.getElementById("customMenu");
myCustomMenu.style.setProperty("--ds-menu-height", "400px");

Setting a height using inline style tag

html
Copy
<div class="ds-autocomplete">
  <div class="ds-input">
    <input type="text" name="test-field" />
  </div>
  <ul class="__list" style="--ds-menu-height: 200px;">
    <li>Anorith</li>
    <li>Arbok</li>
    <li>Arcanine</li>
    <li>Bulbasaur</li>
    <li>Butterfree</li>
    <li>Caterpie</li>
    <li>Charizard</li>
    <li>Charmander</li>
    <li>Charmeleon</li>
    <li>Squirtle</li>
    <li>Venusaur</li>
    <li>Wartortle</li>
  </ul>
</div>
  • Anorith
  • Arbok
  • Arcanine
  • Bulbasaur
  • Butterfree
  • Caterpie
  • Charizard
  • Charmander
  • Charmeleon
  • Squirtle
  • Venusaur
  • Wartortle

Loading state

A details can be triggered to display a loading state - where the details contents are hidden, and the replaced by a centered spinning loading icon – without affecting the dimensions of the details.

Additional options are available using Message state

Default

html
Copy
<div class="ds-autocomplete">
  <div class="ds-input">
    <input type="text" name="test-field" />
  </div>
  <ul class="__list --loading">
    <li>Anorith</li>
    <li>Arbok</li>
    <li>Arcanine</li>
    <li>Bulbasaur</li>
    <li>Butterfree</li>
    <li>Caterpie</li>
    <li>Charizard</li>
    <li>Charmander</li>
    <li>Charmeleon</li>
  </ul>
</div>
  • Anorith
  • Arbok
  • Arcanine
  • Bulbasaur
  • Butterfree
  • Caterpie
  • Charizard
  • Charmander
  • Charmeleon

Alternative loading-refresh icon

html
Copy
<div class="ds-autocomplete">
  <div class="ds-input">
    <input type="text" name="test-field" />
  </div>
  <ul class="__list --loading --loading-refresh">
    <li>Anorith</li>
    <li>Arbok</li>
    <li>Arcanine</li>
    <li>Bulbasaur</li>
    <li>Butterfree</li>
    <li>Caterpie</li>
    <li>Charizard</li>
    <li>Charmander</li>
    <li>Charmeleon</li>
  </ul>
</div>
  • Anorith
  • Arbok
  • Arcanine
  • Bulbasaur
  • Butterfree
  • Caterpie
  • Charizard
  • Charmander
  • Charmeleon

Custom icon by adding any icon class

html
Copy
<div class="ds-autocomplete">
  <div class="ds-input">
    <input type="text" name="test-field" />
  </div>
  <ul class="__list --loading --icon-radar">
    <li>Anorith</li>
    <li>Arbok</li>
    <li>Arcanine</li>
    <li>Bulbasaur</li>
    <li>Butterfree</li>
    <li>Caterpie</li>
    <li>Charizard</li>
    <li>Charmander</li>
    <li>Charmeleon</li>
  </ul>
</div>
  • Anorith
  • Arbok
  • Arcanine
  • Bulbasaur
  • Butterfree
  • Caterpie
  • Charizard
  • Charmander
  • Charmeleon

Message state

Message state extends and can be used with Loading state. If a details has a data-attribute data-ds-message the details contents are hidden, and replaced by an icon and the text of the data-ds-message.

html
Copy
<div class="ds-autocomplete">
  <div class="ds-input">
    <input type="text" name="test-field" />
  </div>
  <ul class="__list" data-ds-message="Message text">
    <li>Anorith</li>
    <li>Arbok</li>
    <li>Arcanine</li>
    <li>Bulbasaur</li>
    <li>Butterfree</li>
    <li>Caterpie</li>
    <li>Charizard</li>
    <li>Charmander</li>
    <li>Charmeleon</li>
  </ul>
</div>
  • Anorith
  • Arbok
  • Arcanine
  • Bulbasaur
  • Butterfree
  • Caterpie
  • Charizard
  • Charmander
  • Charmeleon

Loading state with a message

html
Copy
<div class="ds-autocomplete">
  <div class="ds-input">
    <input type="text" name="test-field" />
  </div>
  <ul class="__list --loading" data-ds-message="Message text">
    <li>Anorith</li>
    <li>Arbok</li>
    <li>Arcanine</li>
    <li>Bulbasaur</li>
    <li>Butterfree</li>
    <li>Caterpie</li>
    <li>Charizard</li>
    <li>Charmander</li>
    <li>Charmeleon</li>
  </ul>
</div>
  • Anorith
  • Arbok
  • Arcanine
  • Bulbasaur
  • Butterfree
  • Caterpie
  • Charizard
  • Charmander
  • Charmeleon

You can set a custom icon

html
Copy
<div class="ds-autocomplete">
  <div class="ds-input">
    <input type="text" name="test-field" />
  </div>
  <ul class="__list --icon-rocket" data-ds-message="Message text">
    <li>Anorith</li>
    <li>Arbok</li>
    <li>Arcanine</li>
    <li>Bulbasaur</li>
    <li>Butterfree</li>
    <li>Caterpie</li>
    <li>Charizard</li>
    <li>Charmander</li>
    <li>Charmeleon</li>
  </ul>
</div>
  • Anorith
  • Arbok
  • Arcanine
  • Bulbasaur
  • Butterfree
  • Caterpie
  • Charizard
  • Charmander
  • Charmeleon

You can set a custom icon, with the loading state animation

html
Copy
<div class="ds-autocomplete">
  <div class="ds-input">
    <input type="text" name="test-field" />
  </div>
  <ul class="__list --loading --icon-compass" data-ds-message="Message text">
    <li>Anorith</li>
    <li>Arbok</li>
    <li>Arcanine</li>
    <li>Bulbasaur</li>
    <li>Butterfree</li>
    <li>Caterpie</li>
    <li>Charizard</li>
    <li>Charmander</li>
    <li>Charmeleon</li>
  </ul>
</div>
  • Anorith
  • Arbok
  • Arcanine
  • Bulbasaur
  • Butterfree
  • Caterpie
  • Charizard
  • Charmander
  • Charmeleon

Input Icons

See ds-input icons.

List icons

See ds-menu icons.

List descriptions

See ds-menu descriptions

Accessibility

Role and ARIA attributes

Recommendations for implementing ds-autocomplete to meet W3C WAI-ARIA guidelines are as follows:

Autocomplete container (div)

html
Copy
<div class="ds-autocomplete">...</div>

Autocomplete combobox (div)

html
Copy
<div
  class="ds-input"
  role="combobox"
  aria-autocomplete="list"
  aria-controls="[ID]"
  aria-expanded="[true|false]"
  aria-activedescendant="[ID]"
>
  ...
</div>
ElementAttributeRequiredTypeDescription
<div>role=“combobox”RequiredStaticIndicates the div is a combobox
aria-autocomplete=“list”RequiredStaticIndicates the combobox is an autocomplete list
aria-controls=“[ID]“RequiredStaticRefers to the ID of the autocomplete list
aria-expanded=“[true|false]“RequiredDynamic1. Set to true when the list is open
2. Removed or set to false when the list is closed
aria-activedescendant=“[ID]“RequiredStaticRefers to the ID of the focused item in the autocomplete list

Autocomplete textbox (input)

html
Copy
<div class="ds-input">
  <input type="text" aria-label="[string]" autocomplete="off" />
</div>
ElementAttributeRequiredTypeDescription
<input type=“text”>aria-label=“[string]“RequiredStaticDescriptive label
autocomplete=“off”RecommendedStaticDisable default browser autocomplete

Autocomplete list (ul)

html
Copy
<ul class="__list" id="[ID]" role="listbox">
  <li id="[ID]" role="option" aria-selected="[true|false]">...</li>
</ul>
ElementAttributeRequiredTypeDescription
<ul>id=“[ID]“RequiredStatic1. Unique ID
2. Related to the combobox aria-controls
role=“listbox”RequiredStaticIndicates the element is an autocomplete list
<li>id=“[ID]“RequiredStatic1. Unique ID
2. Related to the combobox aria-activedescendant
role=“option”RequiredStaticIndicates the element is an autocomplete list option
aria-selected=“[true|false]“RequiredDynamicIndicates when the option is selected

Keyboard access

The following keyboard controls must be implemented to provide accessible keyboard access.

Autocomplete textbox (input):

Default browser support for entering and editing text inputs applies, such as delete, left/right arrow.

KeyRequiredTypeDescription
EnterRequiredJavascript1. If a list item is selected, sets the value of the textbox to the selected option.
2. Closes the autocomplete list.
EscapeRequiredJavascript1. Closes the autocomplete list.
2. Clears the textbox.
Down ArrowRequiredJavascript1. If no list item is focused, moves focus to the first list item.
2. If a list item is focused, moves to the next item.
3. If the last item is focused, moves to the first list item.
Up ArrowRequiredJavascript1. If no list item is focused, moves focus to the last list item.
2. If a list item is focused, moves to the previous item.
3. If the first item is focused, moves to the last list item.
Printable CharactersRequiredJavascript1. Types the character in the textbox.
2. Filters the items in the Autocomplete list.
3. Selects the first matching item.

Autocomplete list (ul):

KeyRequiredTypeDescription
EnterRequiredJavascript1. If a list item is selected, sets the value of the textbox to the selected option.
2. Closes the autocomplete list.
3. Move focus to the textbox.
EscapeRequiredJavascript1. Closes the autocomplete list.
2. Clears the textbox.
3. Sets focus to the textbox.
Down ArrowRequiredJavascript1. Moves to the next item.
2. If the last item is selected, moves to the first list item.
Up ArrowRequiredJavascript1. Moves to the previous item.
2. If the first item is selected, moves to the last list item.
Left ArrowRequiredJavascript1. Move focus to the textbox.
2. Moves cursor one character to left.
Right ArrowRequiredJavascript1. Move focus to the textbox.
2. Moves cursor one character to right.
HomeRequiredJavascript1. Move focus to the textbox.
2. Moves cursor to beginning of the textbox.
endRequiredJavascript1. Move focus to the textbox.
2. Moves cursor to end of the textbox.
Printable CharactersRequiredJavascript1. Move focus to the textbox.
2. Types the character in the textbox.

Examples

Used within ds-field, with label and --addon

html
Copy
<div class="ds-field">
  <label for="example-1" class="ds-text --label">Field test</label>
  <div
    class="ds-autocomplete"
    role="combobox"
    aria-haspopup="listbox"
    aria-owns="example-1-list"
  >
    <div class="ds-input">
      <input
        type="text"
        name="example-1-input"
        id="example-1-input"
        aria-autocomplete="list"
        aria-controls="example-1-list"
      />
    </div>
    <ul id="example-1-list" class="__list">
      <li role="option" id="option-anorith">Anorith</li>
      <li role="option" id="option-arbok">Arbok</li>
      <li role="option" id="option-arcanine">Arcanine</li>
      <li role="option" id="option-bulbasaur">Bulbasaur</li>
      <li role="option" id="option-butterfree">Butterfree</li>
      <li role="option" id="option-caterpie">Caterpie</li>
      <li role="option" id="option-charizard">Charizard</li>
      <li role="option" id="option-charmander">Charmander</li>
      <li role="option" id="option-charmeleon">Charmeleon</li>
      <li role="option" id="option-squirtle">Squirtle</li>
      <li role="option" id="option-venusaur">Venusaur</li>
      <li role="option" id="option-wartortle">Wartortle</li>
    </ul>
  </div>
</div>
  • Anorith
  • Arbok
  • Arcanine
  • Bulbasaur
  • Butterfree
  • Caterpie
  • Charizard
  • Charmander
  • Charmeleon
  • Squirtle
  • Venusaur
  • Wartortle

Autocomplete list with rich content

html
Copy
<div class="ds-autocomplete">
  <div class="ds-input">
    <input type="text" name="test-field" />
  </div>
  <ul class="__list">
    <li data-ds-value="019281919281">
      <dl class="ds-details--vertical">
        <dt>Sim ID: 019281919281</dt>
        <dd>
          <div>My SIM</div>
          <div class="ds-text --small --success --icon-online">Online</div>
        </dd>
      </dl>
    </li>
    <li data-ds-value="9381273784832">
      <dl class="ds-details--vertical">
        <dt>Sim ID: 9381273784832</dt>
        <dd>
          <div>My Other SIM</div>
          <div class="ds-text --small --alert --icon-online">Offline</div>
        </dd>
      </dl>
    </li>
    <li data-ds-value="9381273784719">
      <dl class="ds-details--vertical">
        <dt>Sim ID: 9381273784719</dt>
        <dd>
          <div>My Other SIM</div>
          <div class="ds-text --small --alert --icon-online">Offline</div>
        </dd>
      </dl>
    </li>
  </ul>
</div>
  • Sim ID: 019281919281
    My SIM
    Online
  • Sim ID: 9381273784832
    My Other SIM
    Offline
  • Sim ID: 9381273784719
    My Other SIM
    Offline

References