skip to Main Content

I’m using a plain text input plus datalist to suggest values as the user interacts with the input. I’d like to know if there’s a way to get the suggested items shown.

E.g.

    document.getElementById('myBrowser').addEventListener('input', function() {
      console.log(this.list.suggested); // logs out the suggested values 
    });
    <label for="myBrowser">Choose a browser from this list:</label>
    <input list="browsers" id="myBrowser" name="myBrowser" />
    <datalist id="browsers">
      <option value="Chrome"></option>
      <option value="Firefox"></option>
      <option value="Opera"></option>
      <option value="Safari"></option>
      <option value="Microsoft Edge"></option>
    </datalist>

So if I type ‘Fire’ the suggestion values should just be [‘Firefox’]

2

Answers


  1. You can do something like this :

    // Obtain the available browsers
    let options = Array.from(document.querySelectorAll('#browsers option')).map((option) => option.value);
    
    document.getElementById('myBrowser').addEventListener('input', function () {
      const hint = this.value.toLowerCase();
      // Obtain options matching input
      const suggestions = options.filter((option) => option.toLowerCase().includes(hint));
    
      console.log(suggestions);
    });
    <label for="myBrowser">Choose a browser from this list:</label>
    <input list="browsers" id="myBrowser" name="myBrowser" />
    <datalist id="browsers">
      <option value="Chrome"></option>
      <option value="Firefox"></option>
      <option value="Opera"></option>
      <option value="Safari"></option>
      <option value="Microsoft Edge"></option>
    </datalist>

    This obtains the exact same list as on Chrome, but that may not be the case on other browsers.

    As for directly accessing the proposed list from the browser, I cannot say for sure if that is doable.

    Login or Signup to reply.
  2. One could implement such an additional suggestedValue property as getter of the HTMLInputElement.prototype.

    The suggested solution has to be implemented as direct property of an input-element and not like the OP suggested … "[inputElement].list.suggested" … as property of a datalist-element … since <datalist/>, via its id-attribute, can be referred to by more than just one element, each via its list-attribute.

    Thus, a possible implementation and usage could look like follows …

    document
      .querySelectorAll('input[list]')
      .forEach(elmInput =>
        elmInput.addEventListener('input', ({ currentTarget }) =>
          console.log({
            currentTarget,
            suggestedValues: currentTarget.suggestedValues,
          })
        )
      );
    body { margin: 0; }
    .as-console-wrapper { min-height: calc(100% - 50px); }
    <div>
      <input placeholder="no browser" />
      <input list="" placeholder="broken browser" />
    </div>
    <div>
      <input list="browser-list" placeholder="my browser" />
      <input list="browser-list" placeholder="your browser" />
    </div>
    
    <datalist id="browser-list">
      <option value="Chrome"></option>
      <option value="Firefox"></option>
      <option value="Opera"></option>
      <option value="Safari"></option>
      <option value="Microsoft Edge"></option>
    </datalist>
    
    <script>
    Object.defineProperty(HTMLInputElement.prototype, 'suggestedValues', {
      get() {
        const search = this.value.trim().replace(/s+/, ' ').toLowerCase();
        const { list } = this;
    
        return (list ?? null) && [
          ...list.options
        ]
        .map(({ value }) => value)
        .filter(value =>
          value.trim().replace(/s+/, ' ').toLowerCase().includes(search)
        );
      },
      enumerable: true,
      configurable: true,
    });
    </script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search