Vue Auto Focus Directive: Managing Automatic Input Focusing

  • Upon page load, focus shifts to the order number input field
  • After scanning a order number, focus moves to the product barcode input
  • Following barcode scanning, focus remains on the barcode input
  • Once all barocdes are scanned, focus returns to the order number input

To address such scenarios, I developed a Vue directive named vue-auto-focus. You can find it on GitHub at vue-auto-focus, and contributions are welcome.

Example Usage

<template>
    <form v-auto-focus="focusControl" :data-current="activeIndex" :data-action="actionType">
        <input @focus="handleFocus(0)" type="text" data-index="0">
        <input @focus="handleFocus(1)" type="text" data-index="1">
        <textarea @focus="handleFocus(2)" name="" id="" cols="30" rows="10" data-index="2"></textarea>
        <input @focus="handleFocus(3)" type="text" data-index="3">
    </form>
</template>

<script>
export default {
    data() {
        return {
            focusControl: 0,
            activeIndex: 0,
            actionType: 'next',
        }
    },
    methods: {
        /**
         * Triggers the auto-focus directive
         * @param actionType {string} Type of focus action: 'next'/'prev'/'first'/'last'/'jump'
         * @param index {string} Target index when actionType is 'jump'
         **/
        setFocus(actionType, index) {
            if (actionType === 'jump') {
                this.activeIndex = index
            }
            this.focusControl++
            this.actionType = actionType
        },
        /**
         * Updates the active index when an element gains focus
         * @param index {number} Index of the focused element
         **/
        handleFocus(index) {
            this.activeIndex = index
        },
    }
}
</script>

Supported Actions

  • next: Move focus to the next element
  • prev: Move focus to the previous element
  • first: Move focus to the first element
  • last: Move focus to the last element
  • jump: Move focus to a specific element

Focus Control Logic

/**
 * Handles focus actions based on directive parameters
 * @param el {Element} The element where the directive is applied
 */
const handleFocusAction = function (el) {
    const action = el.dataset.action
    const focusElements = getAllFocusElements(el)
    const totalElements = focusElements.length
    let currentIndex = getActiveIndex(el, focusElements)
    
    switch (action) {
        case 'next':
            if (currentIndex <= totalElements - 1) {
                currentIndex++
            }
            focusElements[currentIndex].focus()
            break
        case 'prev':
            if (currentIndex > 0) {
                currentIndex--
            }
            focusElements[currentIndex].focus()
            break
        case 'first':
            currentIndex = 0
            focusElements[currentIndex].focus()
            break
        case 'last':
            currentIndex = totalElements - 1
            focusElements[currentIndex].focus()
            break
        case 'jump':
            if (currentIndex >= 0 && currentIndex < totalElements) {
                focusElements[currentIndex].focus()
            }
            break
    }
}

Each focusable element must have a data-index attribute. The parent container requires data-action and data-current attributes to define the focus behavior and current position respectively.

/**
 * Retrieves all focusable elements with data-index attribute
 * @param parentElement {Element} The directive's container element
 * @returns {NodeList} List of focusable elements
 */
const getAllFocusElements = function (parentElement) {
    return parentElement.querySelectorAll('[data-index]')
}

/**
 * Determines the index of the currently focused element
 * @param el {Element} Directive container
 * @param elements {Array} List of focusable elements
 * @returns {number} Index of the active element
 */
const getActiveIndex = function(el, elements) {
    const targetElement = document.querySelector(`[data-index="${el.dataset.current}"]`)
    return Array.from(elements).indexOf(targetElement)
}

Directive Lifecycle Hooks

Inserted Hook

Automatically focuses on the designated element upon component mounting.

inserted: function (el) {
    const focusElements = getAllFocusElements(el)
    let currentIndex = getActiveIndex(el, focusElements)
    
    if (currentIndex < 0 || currentIndex >= focusElements.length) {
        currentIndex = 0
    }
    
    focusElements[currentIndex].focus()
},

Update Hook

Executes focus changes whenever the directive's value updates.

update: function (el, binding) {
    if (binding.value !== binding.oldValue) {
        handleFocusAction(el)
    }
},

Tags: vue directive focus form input

Posted on Mon, 18 May 2026 04:00:36 +0000 by Cynix