darrenjennings / vue-autosuggest

🔍 Vue autosuggest component.
https://darrenjennings.github.io/vue-autosuggest
MIT License
621 stars 91 forks source link

[before|after]-input no longer adjacent to input #205

Closed jenglish404 closed 3 years ago

jenglish404 commented 4 years ago

Problem description:

In the most recent change, it looks like a div was added as a wrapper around the input:

<slot name="before-input" /><div
      role="combobox"
      :aria-expanded="isOpen ? 'true' : 'false'"
      aria-haspopup="listbox"
      :aria-owns="`${componentAttrIdAutosuggest}-${componentAttrPrefix}__results`"
    ><input
      :type="internal_inputProps.type"
      :value="internalValue"
      :autocomplete="internal_inputProps.autocomplete"
      :class="[isOpen ? `${componentAttrPrefix}__input--open` : '', internal_inputProps['class']]"
      v-bind="internal_inputProps"
      aria-autocomplete="list"
      :aria-activedescendant="isOpen && currentIndex !== null ? `${componentAttrPrefix}__results-item--${currentIndex}` : ''"
      :aria-controls="`${componentAttrIdAutosuggest}-${componentAttrPrefix}__results`"
      @input="inputHandler"
      @keydown="handleKeyStroke"
      v-on="listeners"
    ></div><slot name="after-input" />

The end result is that the [before|after]-input slots are now before|after the div, not the input. We were using the after-input slot along with some Sass that relies on the label being adjacent to the input (input + label):

input[type='text'] {
  & + label {
      font-size: 12px;
      position: absolute;
      top: -10px;
      left: 14px;
      opacity: 0;
      color: transparent;
      @include transition-all;
  }

  // input focus
  &:focus {
    &::placeholder {
        color: transparent;
      }
  }

  &:not(:placeholder-shown) {
      & + label {
        top: -17px;
        left: 5px;
        opacity: 1;
      }

      &::placeholder {
        color: transparent;
      }
    }
}

Here's what that looks like in action (label floats above input when input receives focus): floating-label

Since the after-input slot is no longer adjacent to the input, it breaks this styling. I tried working around this, but there's no sibling-of-parent CSS selector (that I'm aware of).

Suggested solution:

Option 1

Revert the change (remove the div wrapper). I see that some of the aria attributes have been shuffled around, so if it needs to be this way then...

Option 2

Move the [before|after]-input slots inside the wrapper so that they're once again adjacent to the input.

I'm happy to make the change and open a PR if that helps.

darrenjennings commented 4 years ago

@jenglish404 can you instead adjust your selectors? The a11y change was important, so would make sense to fix any css that relies on html hierarchy in userland vs. having the label or any other before/after slot content be contained inside of a role="comboxbox". The html from the combobox wai-aria spec suggests putting the label outside:


<label for="ex1-input"
       id="ex1-label"
       class="combobox-label">
  Choice 1 Fruit or Vegetable
</label>
<div class="combobox-wrapper">
  <div role="combobox"
       aria-expanded="false"
       aria-owns="ex1-listbox"
       aria-haspopup="listbox"
       id="ex1-combobox">
    <input type="text"
           aria-autocomplete="list"
           aria-controls="ex1-listbox"
           id="ex1-input">
  </div>
  <ul aria-labelledby="ex1-label"
      role="listbox"
      id="ex1-listbox"
      class="listbox hidden">
  </ul>
</div>```
jenglish404 commented 4 years ago

No worries. I was able to get this to work by adding focus and focusout listeners on the vue-autosuggest component:

<vue-autosuggest
        :suggestions="suggestions"
        :input-props="inputProps"
        :get-suggestion-value="getSuggestionValue"
        @selected="onResultSelected"
        @keypress="handleKeypress"
        @input="onInputChange"
        @focus="onInputFocus"
        @focusout="onInputFocusout"
      >
 ...

...where onInputFocus and onInputFocusout toggle a flag that can be used to set a class on the outer container and subsequently style the label to match the rest of our site.

Thank you so much for the speedy reply!