Environment
Vuetify Version: 4.1.10
Vue Version: 3.x
OS: Not specified
Steps to reproduce
- Put a template ref on a
v-checkbox, v-radio-group, v-switch or v-color-input
- Call
ref.value.focus()
<template>
<v-checkbox ref="checkbox" label="VCheckbox" />
</template>
<script setup>
import { useTemplateRef, onMounted } from 'vue'
const checkbox = useTemplateRef('checkbox')
onMounted(() => checkbox.value.focus())
</script>
Expected Behavior
The control receives focus, as it does on every sibling input — VTextField, VTextarea, VFileInput, VSelect, VAutocomplete, VCombobox, VNumberInput, VDateInput, VSlider, VRangeSlider and VOtpInput all expose a working focus().
Actual Behavior
TypeError: focus is not a function — the method does not exist.
Probed in a real browser against 4.1.10:
[VCheckbox] typeof focus = undefined | THREW TypeError | exposes: reset, validate, resetValidation, isValid
[VRadioGroup] typeof focus = undefined | THREW TypeError | exposes: reset, validate, resetValidation, isValid
[VSwitch] typeof focus = undefined | THREW TypeError | exposes: reset, validate, resetValidation, isValid
[VColorInput] typeof focus = undefined | THREW TypeError | exposes: NOTHING
[VTextField] typeof focus = function | ok, activeElement = <input type=text> | exposes: focus, blur, reset, validate, resetValidation, isValid
Reproduction Link
https://play.vuetifyjs.com/#...
Other comments
Reported by @userquin in Discord; filed on their behalf. Four separate defects, three sharing one cause.
1–3. VCheckbox, VRadioGroup, VSwitch forward refs to a dead end.
All three end with:
return forwardRefs({}, inputRef) // inputRef is the VInput wrapper
and VInput's setup returns only { reset, resetValidation, validate, isValid, errorMessages } — no focus, no element. So there is nothing for focus() to resolve to. That matches the probe exactly: the four validation members are present, focus/blur are not.
The fix has a precedent in-repo — VSlider/VRangeSlider:
return forwardRefs({ focus: () => thumbContainerRef.value?.$el.focus() }, inputRef)
For checkbox/switch no DOM query is needed: VSelectionControl already returns { isFocused, input }, where input is the native <input>. VRadioGroup needs group semantics — focus the checked radio, falling back to the first, since that is the group's tab stop.
4. VColorInput exposes nothing at all. Its setup (VColorInput.tsx:76) ends after useRender with no return statement and the file contains no refs, so it wraps a VTextField and discards that component's entire public API — not only focus() but reset(), validate(), resetValidation(), isValid and errorMessages. VDateInput and VNumberInput are the same wrapper shape and do forwardRefs({}, vTextFieldRef); one line would fix all of it.
Related: VRadioGroup does not emit update:focused. VCheckbox (:44) and VSwitch (:87) both declare it; VRadioGroup does not, so there is no way to observe its focus state either.
Related: programmatic focus cannot restore the focus ring. VSelectionControl gates .v-selection-control--focus-visible (VSelectionControl.sass:96) on the JS flag isFocusVisible (VSelectionControl.tsx:267), which is only ever set inside onFocus (:192-199). Calling .focus() on an already-focused input fires no focus event, so the ring never reappears — even with focus({ focusVisible: true }). If the new focus() accepts FocusOptions, it should set isFocusVisible directly when options.focusVisible is true rather than infer it from the event. The browser heuristic should stay in place for user-initiated focus; this is only about making an explicit programmatic call authoritative.
Source references
packages/vuetify/src/components/VCheckbox/VCheckbox.tsx:101
packages/vuetify/src/components/VRadioGroup/VRadioGroup.tsx:139
packages/vuetify/src/components/VSwitch/VSwitch.tsx:303
packages/vuetify/src/components/VColorInput/VColorInput.tsx:76
packages/vuetify/src/components/VInput/VInput.tsx:263-269
packages/vuetify/src/components/VSelectionControl/VSelectionControl.tsx:192-199, :267, :330
packages/vuetify/src/components/VSlider/VSlider.tsx — the pattern to copy
Environment
Vuetify Version: 4.1.10
Vue Version: 3.x
OS: Not specified
Steps to reproduce
v-checkbox,v-radio-group,v-switchorv-color-inputref.value.focus()Expected Behavior
The control receives focus, as it does on every sibling input —
VTextField,VTextarea,VFileInput,VSelect,VAutocomplete,VCombobox,VNumberInput,VDateInput,VSlider,VRangeSliderandVOtpInputall expose a workingfocus().Actual Behavior
TypeError: focus is not a function— the method does not exist.Probed in a real browser against
4.1.10:Reproduction Link
https://play.vuetifyjs.com/#...
Other comments
Reported by @userquin in Discord; filed on their behalf. Four separate defects, three sharing one cause.
1–3.
VCheckbox,VRadioGroup,VSwitchforward refs to a dead end.All three end with:
and
VInput's setup returns only{ reset, resetValidation, validate, isValid, errorMessages }— nofocus, no element. So there is nothing forfocus()to resolve to. That matches the probe exactly: the four validation members are present,focus/blurare not.The fix has a precedent in-repo —
VSlider/VRangeSlider:For checkbox/switch no DOM query is needed:
VSelectionControlalready returns{ isFocused, input }, whereinputis the native<input>.VRadioGroupneeds group semantics — focus the checked radio, falling back to the first, since that is the group's tab stop.4.
VColorInputexposes nothing at all. Itssetup(VColorInput.tsx:76) ends afteruseRenderwith no return statement and the file contains no refs, so it wraps aVTextFieldand discards that component's entire public API — not onlyfocus()butreset(),validate(),resetValidation(),isValidanderrorMessages.VDateInputandVNumberInputare the same wrapper shape and doforwardRefs({}, vTextFieldRef); one line would fix all of it.Related:
VRadioGroupdoes not emitupdate:focused.VCheckbox(:44) andVSwitch(:87) both declare it;VRadioGroupdoes not, so there is no way to observe its focus state either.Related: programmatic focus cannot restore the focus ring.
VSelectionControlgates.v-selection-control--focus-visible(VSelectionControl.sass:96) on the JS flagisFocusVisible(VSelectionControl.tsx:267), which is only ever set insideonFocus(:192-199). Calling.focus()on an already-focused input fires no focus event, so the ring never reappears — even withfocus({ focusVisible: true }). If the newfocus()acceptsFocusOptions, it should setisFocusVisibledirectly whenoptions.focusVisibleis true rather than infer it from the event. The browser heuristic should stay in place for user-initiated focus; this is only about making an explicit programmatic call authoritative.Source references
packages/vuetify/src/components/VCheckbox/VCheckbox.tsx:101packages/vuetify/src/components/VRadioGroup/VRadioGroup.tsx:139packages/vuetify/src/components/VSwitch/VSwitch.tsx:303packages/vuetify/src/components/VColorInput/VColorInput.tsx:76packages/vuetify/src/components/VInput/VInput.tsx:263-269packages/vuetify/src/components/VSelectionControl/VSelectionControl.tsx:192-199,:267,:330packages/vuetify/src/components/VSlider/VSlider.tsx— the pattern to copy