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.
This commit is contained in:
kolaente 2026-01-08 19:53:34 +01:00
parent bad314b5e3
commit ddd5662d66
1 changed files with 17 additions and 2 deletions

View File

@ -1,6 +1,20 @@
import type {Directive} from 'vue'
const focus = <Directive<HTMLElement,string>>{
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<HTMLElement>('input, select, textarea, [contenteditable="true"]')
}
const focus = <Directive<HTMLElement, string>>{
// 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 = <Directive<HTMLElement,string>>{
// 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()
}
},
}