mskocik / svelecte

Flexible autocomplete/select component written in Svelte,
https://svelecte.vercel.app
MIT License
469 stars 42 forks source link

Feature request: Provide a prop to prevent automatic selection of first dropdown item #162

Closed scoopandrun closed 1 year ago

scoopandrun commented 1 year ago

The automatic setting of dropdownActiveIndex to listIndex.first can be annoying depending on the use case.

Example use case

The component has selectOnTab set to true. The user uses the keyboard to navigate the form and the Svelecte component gets the focus, the dropdown opens automatically and the first item is highlighted. The user doesn't want to select anything and wishes to focus the next element on the form, so they hit Tab but the first item of the dropdown is selected and the value of the Svelecte component is set to this first item.
To avoid this, the user should hit Escape to close the dropdown before hitting Tab to switch to the next element, but this can be non-intuitive and "annoying" when there are several Svelecte components in a row in this situation.

A solution would be to expose a boolean prop (let's say autoHighlightFirstItem, default true to keep the current behavior untouched) and check for this value before setting dropdownActiveIndex.

Example implementation

<script>
  export let autoHighlightFirstItem = true;

  // ...

  $: {
    // Reset index to null if the input has been cleared and autoHighlightFirstItem is set to false
    if (!autoHighlightFirstItem && !$inputValue) {
      dropdownActiveIndex = null;
    }

    // Check autoHighlightFirstItem before setting dropdownActiveIndex
    if (dropdownActiveIndex === null && (autoHighlightFirstItem || $inputValue)) {
      dropdownActiveIndex = listIndex.first;
    } else if (dropdownActiveIndex > listIndex.last) {
      dropdownActiveIndex = listIndex.last;
    } else if (dropdownActiveIndex < listIndex.first) {
      dropdownActiveIndex = listIndex.first;
    }
  }

  // ...

  function onKeyDown(event) {
    // ...
    case 'ArrowDown':
      // ...
      dropdownActiveIndex = dropdownActiveIndex === null ? listIndex.first : listIndex.next(dropdownActiveIndex);

    // ..
  }

  // ...

  onMount(() => {
    // ...

    // dropdownActiveIndex = listIndex.first; // <-- redundant with the $: block

    // ..
  });
</script>

I would write a pull request but I don't know in which branch to include this modification (fork of master or v4?).

mskocik commented 1 year ago

That's the caveat of using selectOnTab, which mixes navigation with action. And no native control has such functionality.

Regarding the feature. Create PR for master. Because v4 is behind in some fixes.