Vuetify: [Bug Report] Tab focus from v-select returns to the first focusable element

Created on 26 Feb 2019  路  25Comments  路  Source: vuetifyjs/vuetify

Versions and Environment

Vuetify: 1.5.1
Vue: 2.6.6
Browsers: Safari, Internet Explorer
OS: Mac OS 10.13.6, Windows

Steps to reproduce

Using macOS Safari 12.0.3 or IE11.

  1. after focusing on v-select
  2. pressing the tab key
  3. does not focus to next focusable element

    • but focus on the beginning of document.

It can be confirmed in the sample of the official document.

In Google Chrome, tab focus move from v-select is works normally.

Expected Behavior

Tab focus move to next focusable element from v-select in Safari and IE11

Actual Behavior

Tab focus does not move to next focusable element from v-select in Safari and IE11

Reproduction Link

https://codepen.io/anon/pen/RdwyQQ?editors=1010

VSelect bug platform specific

Most helpful comment

@johnleider will be applied to 1.5 version?

All 25 comments

This issue is also happening on chrome windows 10 not only v-select but also on v-autocomplete or any dropdown input. When the user selecting an item with the help of the mouse and then press tab key is not working properly as expected. When the mosue click to select an item and tab three times then focus moving onto first input.

Is there any work around for this?

Any news about this? A month has passed and there is still no work around for this!!!

It seems that the order in which the events are emitted by the browser are disparate, so when one component lost focus and other receive it may be diffferent in sequence between disparate browsers. So, the solution could be to give a chance to the browser to do its work and then process the event to work around this problem.

A simple work around is to extends for example VAutocomplete:

import { VAutocomplete } from "vuetify/lib";
export default {
  name: "your-autocomplete",
  extends: VAutocomplete,
  methods: {
    blur(e) {
      setTimeout(() => VAutocomplete.methods.blur.call(this, e), 0);
    }
  }
};

On MS Edge this work around works, I need to check it on Safari: by the way, this is a pen to prove that works: https://codepen.io/userquin/pen/rRaYgP

also working on safari macosx

Blame: 8a2a1a1b6974ec264e974866b0775f2820dc3503

@johnleider that logic needs to be in a separate method, this fix is also emitting blur twice.

I'll try to fix that, maybe we need to stop first one to avoid bubbling and just propagate only from onBlur inside VXXX: just add e.stopPropagation() to cancel bubbling.

From w3c, event bubbling:

Any event handler may choose to prevent further event propagation by calling the stopPropagation method of the Event interface. If any EventListener calls this method, all additional EventListeners on the current EventTarget will be triggered but bubbling will cease at that level. Only one call to stopPropagation is required to prevent further bubbling.

I have version 1.5.5, the code on VSelect is the following (why calling input blur if the event comes from it??):

/** @public */
blur: function blur(e) {
    this.isMenuActive = false;
    this.isFocused = false;
    this.$refs.input && this.$refs.input.blur();
    this.selectedIndex = -1;
    this.onBlur(e);
},

/** @public */
activateMenu: function activateMenu() {
    this.isMenuActive = true;
},

onBlur: function onBlur(e) {
    this.$emit('blur', e);
},

If I just change my autocomplete to this one, just only 1 blur event is fired:

import { VAutocomplete } from "vuetify/lib";
export default {
  name: "your-autocomplete",
  extends: VAutocomplete,
  methods: {
    blur() {
      setTimeout(this.handleBlur, 0);
    },
    handleBlur() {
      this.isMenuActive = false;
      this.isFocused = false;
      this.selectedIndex = -1;
    }
  }
};

The above fix works for the autocomplete, any solution for the VSelects being broken?

Just extends from VSelect instead VAutocomplete, the code for blur method resides on VSelect (test if this works, I dont use VSelect on my projects) :

import { VSelect } from "vuetify/lib";
export default {
  name: "your-select",
  extends: VSelect,
  methods: {
    blur() {
      setTimeout(this.handleBlur, 0);
    },
    handleBlur() {
      this.isMenuActive = false;
      this.isFocused = false;
      this.selectedIndex = -1;
    }
  }
};

also the fix is for 1.5.5, not tested on 1.5.6, 1.5.7

well, it is a little more complicated, just because VSelect is a functional wrapper over VSelect, so we need to import VSelect manually. This fix is tested only on MS Edge:

import VSelect from "vuetify/lib/components/VSelect/VSelect";
// work around for https://github.com/vuetifyjs/vuetify/issues/6608
export default {
  name: "your-select",
  extends: VSelect,
  data: () => ({
    blurHandled: false
  }),
  methods: {
    blur() {
      if (!this.blurHandled) {
        setTimeout(this.handleBlur, 0);
      }
    },
    onTabDown(e) {
      this.blurHandled = true;
      setTimeout(() => this.handleTabDown(e), 0);
    },
    handleBlur() {
      this.isMenuActive = false;
      this.isFocused = false;
      this.selectedIndex = -1;
      this.$nextTick(() => (this.blurHandled = false));
    },
    handleTabDown(e) {
      if (this.isMenuActive) {
        VSelect.options.methods.onTabDown.call(this, e);
      } else {
        this.handleBlur();
      }
    }
  }
};

Thanks, that fix works for 1.57 in IE 11.

a simplified version of VSelect:

import VSelect from "vuetify/lib/components/VSelect/VSelect";
// work around for https://github.com/vuetifyjs/vuetify/issues/6608
export default {
  name: "your-select",
  extends: VSelect,
  methods: {
    blur() {},
    onTabDown(e) {
      setTimeout(() => this.handleTabDown(e), 0);
    },
    handleBlur() {
      this.isMenuActive = false;
      this.isFocused = false;
      this.selectedIndex = -1;
    },
    handleTabDown(e) {
      if (this.isMenuActive) {
        VSelect.options.methods.onTabDown.call(this, e);
      } else {
        this.handleBlur();
      }
    }
  }
};

@KaelWD , will this be fixed any time soon?

both fixes tested on windows 10: edge. chrome and firefox and macosx: chrome, firefox and safari

@KaelWD I think vuetify team must review focus/blur behavior in deep, not just for these 2 components.

Another example (not yet reported): I use a VTextField with a mask for edition (component is focused) and no mask when no focused. All works fine but on safari this VTextField on blur just focus its input again and there is no way to focus another element on the page, I must close the browser. On MS Edge, this VTextField lost the focus on second Tab key.

ok, I just have found what's the problem, it is a problem in the Maskable mixin.

As you can see in the next image (MS Edge), once the tab key is pressed on Fecha Nacimiento (birth date) , then Lugar de nacimiento (Place of birth) gets focused, but the caret is on the first one.

image

What happens here: well, the date component just remove the mask on blur, but Maskable do this:

  watch: {
    /**
     * Make sure the cursor is in the correct
     * location when the mask changes
     */
    mask () {
      ... (some code)
      this.$nextTick(() => {
        this.$refs.input.value = newValue
        this.setCaretPosition(selection)
      })
    }
}
  methods: {
    setCaretPosition (selection) {
      this.selection = selection
      window.setTimeout(() => {
        this.$refs.input && this.$refs.input.setSelectionRange(this.selection, this.selection)
      }, 0)
    },
  ....

In the case of MS Edge, just works and if we press tab key again, the focus moves to the next one bellow Lugar de nacimiento (birth place), and looks like the focus jumps 2 fields (but only jumps 1, the focus is on the second one).

On Safari, the problem is that when you call setSelectionRange, then the field gets focused.

So my work around is very simple:

import VTextField from "vuetify/lib/components/VTextField/VTextField";
export default {
  name: "my-maskable-text-field",
  extends: VTextField,
  methods: {
    setCaretPosition(selection) {
      this.selection = selection;
      setTimeout(() => {
        this.$refs.input &&
          this.isFocused && /*<=== fix here */
          this.$refs.input.setSelectionRange(this.selection, this.selection);
      }, 0);
    }
  }
};

+1

Any update on this? It's a showstopper for us :(

Using this for VCombobox which is also affected by this bug:

import { VCombobox } from 'vuetify/lib'

export default {
  name: 'combobox',
  extends: VCombobox,
  methods: {
    onTabDown(e) {
      setTimeout(() => VCombobox.methods.onTabDown.call(this, e), 0)
    }
  }
}

They apparently changed it to onTabDown instead of blur.

This is resolved with 5fa6a68 . Thank you to everyone for your patience on this.

@johnleider will be applied to 1.5 version?

So these fixes are not going to be in v1.5.x? I am in final stages of beta on a product and we don't have time to try and upgrade to v2.x before launch.

For all who make it this far - I have put up the PR to v1.5 here: https://github.com/vuetifyjs/vuetify/pull/10620. Once this is merged then it should be fixed for all of us who are unable to upgrade to 2.x at this time.

Update It was merged so v1.5.23 has the tabbing fix I applied now.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cawa-93 picture cawa-93  路  3Comments

ricardovanlaarhoven picture ricardovanlaarhoven  路  3Comments

dohomi picture dohomi  路  3Comments

dschreij picture dschreij  路  3Comments

milleraa picture milleraa  路  3Comments