Max100's avatar

How to set focus on a newly shown input element

I'm using Vue 3 with the composition api and I'm having difficulty setting the focus on an input element after it is conditionally shown.

My form has a select element with a button next to it. If the button is clicked, I want to hide the select and show the input element with focus on the input. I'm able to hide the select and show the input, but I can't get to focus on the input. I've tried using v-if and v-show, but either way, I can't get the focus set.

It seems the focus call executes before the input is rendered or shown. I tried putting a delay between the show and the focus, but no luck so far.

Has anybody run into this issue? Also, using the composition api , so I think it needs to work within the script setup.

Thanks

0 likes
5 replies
LaryAI's avatar
Level 58

One solution to this problem is to use a ref to the input element and then use the $nextTick method to set the focus after the input has been rendered. Here's an example:

<template>
  <div>
    <select v-if="!showInput">
      <!-- options here -->
    </select>
    <input ref="myInput" v-show="showInput">
    <button @click="showInput = true">Show Input</button>
  </div>
</template>

<script>
import { ref, nextTick } from 'vue';

export default {
  setup() {
    const showInput = ref(false);
    const myInput = ref(null);

    const setFocus = () => {
      nextTick(() => {
        myInput.value.focus();
      });
    };

    return {
      showInput,
      myInput,
      setFocus,
    };
  },
};
</script>

In this example, we use a ref to the input element and set it to null initially. When the "Show Input" button is clicked, we set the showInput ref to true, which will show the input element. We also call the setFocus method, which will use the $nextTick method to set the focus on the input element after it has been rendered.

Note that we wrap the focus call in the $nextTick method to ensure that it is executed after the input has been rendered. This is because Vue updates the DOM asynchronously, so we need to wait for the next tick before setting the focus.

Also note that we use v-show instead of v-if to ensure that the input element is rendered even if it is initially hidden. This is because v-if will remove the element from the DOM if it is false, which can cause issues with setting the focus.

2 likes
Max100's avatar
Max100
OP
Best Answer
Level 6

@LaryAI Lary's reply didn't work out of the box, but it was helpful starting me down the right path.

For anyone who runs into this issue using Vue 3, here's the answer:

First import nextTick from Vue. Then make your click function asynchronous and call nextTick after showing the element but before the focus call, like this:

async function addNewType() {
    form.adding_type = true;   // hides the select and shows the input
    await nextTick();          // waits until the DOM is reset and ready
	document.getElementById('form.newType').focus();  // sets the focus on the input
}

Thanks for your help, Lary :)

1 like
Max100's avatar
Level 6

@michaelyousrie Glad it was helpful!
Fwiw, these days when using nextTick(), I skip the async and await keywords this way:

function addNewType() {
    form.adding_type = true;   // hides the select and shows the input
    nextTick( () => {         // waits until the DOM is reset and ready
        document.getElementById('form.newType').focus();  // sets focus
    });
}

Either way should work, but this seems slightly cleaner visually.

1 like

Please or to participate in this conversation.