12

I would like to trigger the input box to focus (and thus keyboard to pop up) when a Vue component appears.

It does not to work on iOS.

I tried using Vue's example directive (here), and HTML5 autoFocus but neither worked.

I created this example in a sandbox (https://codesandbox.io/s/lw321wqkm).

FWIW, I do not believe it is a JS limitation, as I've seen example work (such as React Native Web using autoFocus- see example)

Parent component

<template>
<div>
  <TextComp v-if='showText' />
  <button @click='showText = !showText'> Show/hide input </button>
</div>
 
</template>
 ...
 

Child component

<template>
<div>
   <input ref='focusMe' type='text'/>
</div>
 
</template>
 
<script>
 
export default {
  name: 'TextComp',
  mounted () {
    this.$refs.focusMe.focus()
  }
}
 
</script>
tony19
  • 125,647
  • 18
  • 229
  • 307
Ycon
  • 1,830
  • 3
  • 27
  • 56

6 Answers6

27

I hope you must have found a solution by now.

But I just wanted to add this for other new users like me.

mounted () {
    this.$refs.focusMe.focus()       // sometime this doesn't work.
  }

Try adding this instead.

this.$nextTick(() => this.$refs.focusMe.focus())

For more info check this

Edit: 14/06/2022

Prashant's answer also helped me understand the nextTick in more depth.

nextTick allows you to execute code after you have changed some data and Vue.js has updated the virtual DOM based on your data change, but before the browser has rendered that change on the page.

Debu Shinobi
  • 2,057
  • 18
  • 21
0

https://v2.vuejs.org/v2/guide/custom-directive.html

In vue's official guide it says auto focus does not work in mobile safari. When the page loads, that element gains focus (note: autofocus doesn’t work on mobile Safari).

In iOS mobile safari, focus() only works when responding to a user interaction, like a click event. See: Mobile Safari: Javascript focus() method on inputfield only works with click?

My guess why it does not work in Vue:

In your Vue example, when you click on the button, it merely inserts a watcher into a batcher queue. A watcher has the information about what needs to update. You can see it as an update action, or update event. And later (almost immediately, at the next tick), Vue reads it (watcher) from the queue, and update the virtual dom / dom subsequently. However, this means, your code focus() is not "inside" a click event handler, rather, it is executed after the click event handler finishes.

I don't know the internal implementation of React though, so cannot explain why it works in the React example.

tony19
  • 125,647
  • 18
  • 229
  • 307
Wang Sheng
  • 780
  • 1
  • 6
  • 18
  • 2
    Yes, thanks, but my question is about a work around. Why can other JS libraries do it but Vue cannot. Does anyone have a suggestion? – Ycon Aug 20 '18 at 05:10
0

You can create a fake input field and focus it during the click event.

<template>
   <div>
     <TextComp v-if='showText' />
     <button @click='onShowText'> Show/hide input </button>
     <input type="text" ref="dummykeyboard" style="opacity:0">
   </div>

</template>
<script>

export default {
  methods:{
    onShowText() {
      this.showText = !this.showText;
      this.$refs.dummykeyboard.focus();
    }
  }
}

</script>
Felix Jr
  • 402
  • 6
  • 10
0

I would go with this solution and it works for me. Just add set timeout and put focus method inside it

<template>
   <div>
     <input ref='focusMe' type='text'/>
   </div>

</template>

<script>

export default {
  name: 'TextComp',
  mounted () {

    setTimeout(() => {
       this.$refs.focusMe.focus();
    }, 500);

  }
}

</script>

EDIT:

Ideally you can use $nextTick to wait until the DOM fully loaded, but sometimes it didn't work. So using setTimeout is just quick workaround to me.

kusiaga
  • 673
  • 1
  • 7
  • 18
0

I would suggest triggering a click event on that field instead of focus

this.showText = !this.showText;
this.$nextTick(function () {
    this.$refs.dummykeyboard.click();
})
jakob
  • 1
  • 2
  • 1
    Why do you suggest this? – Flame Jul 26 '21 at 19:24
  • Triggering a click on an input element lets the mobile browser handle all relevant events (including focus) and their triggers. I've been in a situation the OP describes and this solution has solved such issues. – jakob Jul 27 '21 at 20:26
-1

Still focus doesn't works for you???

Here is the solution :

setTimeout(() => {
  this.$refs["input-0"].focus();
}, 1000);

The trick is to use setTimeout.

Parth Developer
  • 1,371
  • 1
  • 13
  • 30