From ddd5662d667d1846be49c4a54c5f667f44928524 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 8 Jan 2026 19:53:34 +0100 Subject: [PATCH] fix(frontend): make v-focus directive work with wrapper components When v-focus is applied to a non-focusable element (like a component wrapper div), it now searches for the first focusable child element (input, select, textarea, or contenteditable) and focuses that instead. This allows v-focus to work correctly with FormField and similar wrapper components. --- frontend/src/directives/focus.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/frontend/src/directives/focus.ts b/frontend/src/directives/focus.ts index 4961c180a..affd57e20 100644 --- a/frontend/src/directives/focus.ts +++ b/frontend/src/directives/focus.ts @@ -1,6 +1,20 @@ import type {Directive} from 'vue' -const focus = >{ +const FOCUSABLE_TAGS = ['INPUT', 'SELECT', 'TEXTAREA'] + +function isFocusable(el: HTMLElement): boolean { + return FOCUSABLE_TAGS.includes(el.tagName) || el.isContentEditable +} + +function getFocusableElement(el: HTMLElement): HTMLElement | null { + if (isFocusable(el)) { + return el + } + // Look for the first focusable child + return el.querySelector('input, select, textarea, [contenteditable="true"]') +} + +const focus = >{ // When the bound element is inserted into the DOM... mounted(el, {modifiers}) { // Focus the element only if the viewport is big enough @@ -8,7 +22,8 @@ const focus = >{ // keyboard always pops up and takes half of the available space on the screen. // The threshhold is the same as the breakpoints in css. if (window.innerWidth > 769 || modifiers?.always) { - el.focus() + const target = getFocusableElement(el) + target?.focus() } }, }