How do I keep the focus on an input, after i click on a button without flickering in Vue 3?

Viewed 889

Script

const amountRef = ref(null);
const amount = ref(0.1);

const insertSuggestion = (e, value) => {
  e.preventDefault();
  e.stopPropagation();
  amount.value = value;
  amountRef.value.focus();
};

Template

<Suggestion
   class="..."
   v-for="suggestion in suggestions"
   :key="suggestion"
   @click="insertSuggestion($event, suggestion)"
>
    {{ suggestion }}
</Suggestion>
<input
   class="..."
   @keyup.enter="handleBuy"
   placeholder="Amount"
   ref="amountRef"
   v-model="amount"
/>

enter image description here

2 Answers

You could try to capture the blur event and add the classes back if the relatedTarget is one of those buttons. Super psuedo code below:

<input
   class="..."
   @keyup.enter="handleBuy"
   @blur="maybeMimicFocus"
   placeholder="Amount"
   ref="amountRef"
   v-model="amount"
/>
maybeMimicFocus (event) {
  if (event.relatedTarget && event.relatedTarget.tagname === 'btn') {
    this.$refs.amountRef.$el.classList.add('the-classes-that-make-it-look-focused')
  }
}

the browser won't have to repaint the dom and therefore this transaction should be so quick that the naked eye won't see it a difference. the only caveat I can see is if there are animations attached to transitioning properties in which those will have to fire.

You can re-focus the input element on the blur event:

<input ref="amountRef" @blur="$refs.amountRef.focus()"/>

Edit

You also need to check the relatedTarget of the blur event to make sure you only re-focus when one of the buttons is clicked.

Note: this solution does not work on Firefox.

<Suggestion
   class="suggestion-btn"
   ...
>
</Suggestion>
<input
   ref="amountRef"
   @blur="onBlur"
/>

onBlur(evt) {
    if (
        evt.relatedTarget &&
        evt.relatedTarget.classList.contains("suggestion-btn")
    ) {
        this.$refs.amountRef.focus();
    }
},
Related