Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

ricardoarg's avatar

Vue: set focus to input created by v-for

say you have something like this, where you have a simple button to add an objec to an array, and a v-for for editing all that options in the array.

How do you set the focus to the newly created input when the user press addOption ?

app.js

var vm = new Vue({
    el: 'body',
    data: {
        myoptions: []
    },
    methods: {
        addOption: function() {
            this.myoptions.push({description: ''});
        }
    }
});
.........

index.html

<button type="button" v-on:click="addOption">Add Option</button><br>
<table>
    <tr v-for="option in options">
        <td><input type="text" v-model="option.description"></td>
    </tr>
</table>
0 likes
7 replies
ricardoarg's avatar

great thanks! It was simpler than I thought.

I did it with this simple directive:

Vue.directive('focus', {
    bind: function () {
        var object = this.el;
        Vue.nextTick(function() {
            object.focus();
        });
    }
});

and adding v-focus to the input.

2 likes
MacPrawn's avatar

Perfect solution - thank you! - except... How does one tell the difference between initial page setup and user-triggered additions?

Imagine you have a list of input fields, and a button to add a new item (field) to the list...

When the user presses the "add" button, I'd like the newly added input field to get focus so the user can start typing without using their mouse to click in the field or use the tab key or anything like that... This solution works great for that.

However, when the page (re-)loads, it will also end-up getting focus to the last item in the list - and I don't want that...

In short, I only want to focus on the field after the "Add" button's been clicked.

Any suggestions?

Thanks!

** UPDATE **

Murphy's rule - found a way just after posting my question...

So for posterity, here's how I got it to work:

  1. I set refs on each list item, in my case since there's no sorting involved, a plain index-based ref is enough:
<ul v-for="(item, index) in items">
    <li>
        <input :ref="'field-'+index">
    </li>
</ul>
  1. Then in my add button's method, I can grab a ref to the newly added field, and call focus on it on nextTick:
this.$nextTick(() => {
    this.$refs["field-" + (this.fields.length - 1)][0].$el.focus()
})

Need additional error checking of course, but that otherwise works.

1 like
lukas.pierce's avatar

By easy way, you can do it without index postfix, because this.$refs.title - its array yet:

<div id="app">
  <ul v-for="item in items">
    <li>
      <input :ref="'title'" v-model="item.title">
    </li>
  </ul>
  <button v-on:click="addItem">Add Item</button>
</div>

and on next tick you have access to input, by index from that array this.$refs.title:

let app = new Vue({
  el: '#app',
  data: {
    items: [
      {title: 'Apple'},
      {title: 'Orange'},
    ]
  },
  methods: {
    addItem(){
       this.items.push({title: "Pineapple"});
       this.$nextTick(() => {
         let index = this.items.length - 1;
         let input = this.$refs.title[index];
         input.focus();
      });
    }
  }
});
7 likes

Please or to participate in this conversation.