27

I worked with Vue2, but I recently try Vue 3.

I have simple problem:

 <input ref="myinput" />
 <button @click="submitData" />

I want to set "focus" on "myinput", inside function "submitData". In Vue 2 it is simple (this.$refs ...), but in Vue 3, they made it complicated. I saw example with "setup", but is no use for me + I think you can only access "value" from element.

Is there any way to execute "focus" on on element inside methods?

9 Answers 9

38

In case someone comes to this question looking for a way to set the autofocus of a specific element in Vue3, you can achieve it using a Vue Custom Directive

const { createApp, onMounted } = Vue;

const app = createApp({})

// Register a global custom directive called `v-focus`
app.directive('focus', {
  // When the bound element is mounted into the DOM...
  mounted(el) {
    // Focus the element
    el.focus()
  }
})

app.mount('#app')
<script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>

<div id="app">
    <input />
    <input v-focus />
    <input />
</div>

Sign up to request clarification or add additional context in comments.

2 Comments

I like the idea. I just would need to figure out how to register this in storybook for the components.
greate solved my
25

You are still able to do the same thing using Vue 3, but if you work with composition api there's some difference :

Options API :

const {
  createApp
} = Vue;
const App = {

  data() {
    return {

    }
  },
  methods: {
    submitData() {
      this.$refs.myinput.focus()
    }
  },
  mounted() {

  }
}
const app = createApp(App)
app.mount('#app')
<script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>

<div id="app">
  Vue 3 app
  <input ref="myinput" />
  <button @click="submitData">
  Submit
  </button>
</div>

composition API:

const {
  createApp,
  ref,
  onMounted,

} = Vue;
const App = {

  setup() {
    const myinput = ref(null)

    function submitData() {
      myinput.value.focus()
    }

    return {
      myinput,
      submitData
    }
  }
}
const app = createApp(App)
app.mount('#app')
<script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>

<div id="app">
  Vue 3 app
  <input ref="myinput" />
  <button @click="submitData">
  Submit
  </button>
</div>

1 Comment

This doesn't work with Vue 3, neither Composition APi nor Options API
16

In some cases when the input is hidden under a v-show or v-if it is necessary to do a nextTick for the focus to work.

<span
    v-show="!editMode"
    @click="handleEditionMode"
>
    {{ content }}
</span>
<input
    v-show="editMode"
    ref="input"
    v-model="content"
    aria-describedby="item-content"
    name="content"
    type="text"
    tabindex="0"
    @focusout="editMode = false"
    @keydown.enter="editMode = false"
/>
const input = ref(null),
    editMode = ref(false);

const handleEditionMode = () => {
    editMode.value = true;
    nextTick(() => {
        input.value.focus();
    });
};

2 Comments

This is the right answer with Vue 3. Don't forget to import the nextTick function at the top of the file (import { nextTick } from 'vue')
Ran into this exact issue focusing a ref on onMounted() in Vue 3. The docs on nextTick() offer some explanation, but really wish it wasn't such a magical black box fix.
15

Easiest answer I found is missing here

<input type="text" autofocus />

3 Comments

This will only work on first page load, or when reloading a page.
Yes, this will only work on page (re)load. But it is the right solution if you want to have an element focused initially on loading the page.
For the vuejs this is not a appropriate solution. :(
2

In the Vue 3 Composable API I found the most straightforward solution was to use document.getElementById(). The trick was to wrap the .focus() call in Vue's nextTick()

/** set focus to predetermined HTML element  */
const setFocusToElement = async () => {
  nextTick(() => {
    const element = document.getElementById('myInputId');
    if (element) {
      element.focus();
    }
  });
};

1 Comment

getElementById is fantastic, the problem with this solution is that getElementById looks for the element in the whole document, if you have more than one instance of your component, you need to identify the element of a specific instance of the component. Not just an element with a certain id or class
2

onMounted didn't work for me I used watchEffect:

<script setup>
   import { ref, watchEffect} from 'vue'

// declare a ref to hold the element reference
// the name must match template ref value
    
    const input = ref<HTMLInputElement | null>(null);
    watchEffect(() => {
        if (input.value) {
            input.value.focus()
        }
    });

</script>

<template>
  <input ref="input" />
</template>

Comments

1

Another vanilla solution is:

document.getElementById("code")?.focus()

to be called on onMounted

Comments

0

I was trying to select a specific input upon loading the form component.

The above examples were not useful, so I figured it out myself.

This is far simpler, IMHO. Add 1 ref tag and 1 line of code in the mounted hook.

Place a ref tag on the item you'd like to focus. Here I named it "formStart" but you can name yours whatever you like.

<form @submit.prevent="createNewRoute">
  <label for="code">Code</label>
  <input v-model="code" id="code" type="text" ref="formStart" /> <!-- REF TAG HERE -->
  <label for="type">Type</label>
  <input v-model="type" id="type" type="text" />
  /* Other inputs hidden for simplicity */
  <button type="submit">Add Route</button>
</form>

Reference that ref tag in the mounted hook and focus() it.

<script>
export default {
  /* Other options hidden for simplicity */
  mounted() {
    this.$refs.formStart.focus(); // FOCUS ELEMENT HERE
  },
};
</script>

Comments

0
       <div
            v-if="openmodal"
            tabindex="0"
            v-focus
            @keydown.right="() => nextimage(1)"
        >
       </div>

i used methods of @webcu and added tabindex="0" it's work!

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.