29

I'm trying to set the focus of an input element in Vue.js. I found some help online but none of the explanation worked for me.

Here's my code :

<template>
    <form method="post" action="" v-on:submit.prevent="search">
        <input type="text" placeholder="Person name" required v-model="name" v-el="nameInput" />
        <input type="text" placeholder="Company" required v-model="company" v-el="domainInput" />
        <input type="submit" value="Search" class="btn show-m" />
    </form>
</template>

<script>
export default {
    data () {
        return {
            contacts: [],
            name: null,
            company: null
        }
    },
    ready: {
        // I tried the following :
        this.$$.nameInput.focus();
        this.$els.nameInput.focus();
        // None of them worked !
    }
    methods: {
        search: function (event) {
            // ...

            // I also would like to give the focus here, once the form has been submitted.
            // And here also, this.$$ and this.$els doesn't work
        },
    }
}
</script>

I tried this.$$.nameInput.focus(); and this.$els.nameInput.focus(); for what I could find online to target the focus, but this.$$ is undefined, and this.$els is empty.

I'm using Vue.js v1.0.15

1

9 Answers 9

55

In vue 2.x you can solve it with a directive.

Vue.directive('focus', {
    inserted: function (el) {
        el.focus()
    }
})

Then you can use v-focus attribute on inputs and other elements:

<input v-focus>
Sign up to request clarification or add additional context in comments.

2 Comments

It did work. But I had to use inserted: function (el) { el.__vue__.focus() } Maybe it's because I use vue element-ui.
And how I can do it via method??
17

Another solution using Vue 2.x and ref.

You can use the ref/$refs attribute to target your input and focus it.

In the example a simple method is used which can target the inputs using the ref attribute supplied to the inputs. Then access the $refs property on your instance to get a reference to the DOM element.

<script>
export default {
    // ...
  mounted: function () {
    this.focusInput('nameInput');
  },
  methods: {
    // This is the method that focuses the element
    focusInput: function ( inputRef ) {
      // $refs is an object that holds the DOM references to your inputs
      this.$refs[inputRef].focus();
    },

    search: function (event) {
      this.focusInput('domainInput');
    },
  }
}
</script>
<template>
  <form method="post" action="" v-on:submit.prevent="search">
    <input type="text" placeholder="Person name" required v-model="name" ref="nameInput" />
    <input type="text" placeholder="Company" required v-model="company" ref="domainInput" />
    <input type="submit" value="Search" class="btn show-m" />
  </form>
</template>

This solution is best for a one off situation or for a reusable component. For a more global approach the directive is the way to go.

Comments

5

Setting focus inside a child element

(for those of you that struggled for hours like me)

Parent:

<template>
  <div @click="$refs.theComponent.$refs.theInput.focus()">
    <custom-input ref="theComponent"/>
  </div>
</template>

Child (CustomInput.vue):

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

1 Comment

Of course it also works without a component, for those who don't want to clutter their code with a directive, but need to focus an input by clicking on an element: @click="$refs.filter_ref.focus()", where filter_ref is the ref of your input.
4

Vue 3.x

Use a custom directive.

app.directive('focus', {
    mounted(el) { 
      el.focus() 
    }
})

Here is how you use it:

Step 1:

// main.js

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

const app = createApp(App)
app.use(router)

 app.directive('focus', {
     mounted(el) { // When the bound element is inserted into the DOM...
       el.focus() // Focus the element
     }
 })

/* Optional: 
   Add a slight delay if the input does not focus.

app.directive('focus', {
    mounted(el) { // When the bound element is inserted into the DOM...
        setTimeout(() => {
            el.focus() // Focus the element
        }, 500)
    }
}) */

await router.isReady()
app.mount('#app')

Then in your component:

Step 2:

// MyInput.vue

<input v-focus>

Vue docs

Comments

3

There are a couple of issues.

First of all, v-els are defined like this:

<input v-el:input-element/>

That'll turn the variable to a camelCase in the code. You can read up more on this weird functionality here.

Other than that, you should be able to access the variable through this.$els.inputElement. Mind you, it will only appear in the component that you're defining that element (or the main app itself, if you defined it there).

Secondly, the automatic focusing does not seem to be working on Firefox (43.0.4), at least on my machine. Everything works great on Chrome, and focuses as expected.

3 Comments

That's odd, why this way of functionning ? (if you have any idea). The v-el="XXX" is more logical no ?
But this works, so you shall have my accepted answer :) Thank you
This is the basic thought process on the current functionality.
2

Using ref I managed to focus an Input on mounted like this.

Template :

 <b-form-input  v-model="query" ref="searchInput" ></b-form-input>

Javascript :

  mounted(){
    this.$refs.searchInput.$el.focus()
  }

2 Comments

Even though correct, the default linter with Vue-cli and Vue will recommend you to use this.$refs.searchInput.$el.focus() ;)
@CyrilN. using $ in object field cannot be used in most of the other languages. So I get confused now and then. Fixed it in the edit.
0

According to vue 2.x, you can also register "directive" locally in component to get autofocus.

just write directive in component:

export default {
  directives: { focus: {
    inserted: function (el) {
    el.focus()
    }
  }
  }
}

Then in a template, you can use the new v-focus attribute on any element, like this:

<input type="text" v-focus>

Comments

0

There is something that needs to be added to these answers here. First of all in my case when I use ref it returns an array. For example I want user to enter a 5 digit number and I have 5 inputs for each digit:

<div v-for="n, i in 5" :key="i">
    <input
        inputmode="numeric"
        type="text"
        v-model="codeDigits[n]"
        autocomplete="off"
        @input="typeOnCodeInput(n)"
        :ref="`code-input-${n}`"
    />
</div>

And in my methods section I have defined a method named "typeOnCodeInput" and in this method I want to select next input and focus on it. So this is how my method is written:

typeOnCodeInput (n) {
this.$refs[`code-input-${n+1}`][0].focus()
}

My Point Is : In some setups this.$refs['code-input-1'] or this.$refs['code-input-2'] or... They all return an array.
So that's why I have that [0] before .focus()

FYI: When I was searching for answers, this array thing was not mentioned in so many answers and it was a key concept to solve the problem in my case. So, I added this answer and it may help some people who have the same issue just like mine

Comments

0

Here we are in 2025... for vue 3, I'm using vuetify but I think it works for all:

template:

...
<v-text-field ref="passwordInput"...
...

js:

<script setup>
const passwordInput     = ref("passwordInput")
passwordInput.value.focus()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.