feat(a11y): associate errors with inputs in FormInput and FormSelect

Wire aria-invalid, aria-describedby and role=alert on the form
primitive components so errors raised directly on FormInput or
FormSelect are announced by assistive tech and programmatically
linked to the control.
This commit is contained in:
kolaente 2026-04-20 21:02:19 +02:00 committed by kolaente
parent fd1a329f5d
commit 2829a851df
2 changed files with 10 additions and 0 deletions

View File

@ -22,6 +22,7 @@ defineOptions({inheritAttrs: false})
const fallbackId = useId()
const inputId = computed(() => props.id ?? fallbackId)
const errorId = computed(() => props.error ? `${inputId.value}-error` : undefined)
const inputClasses = computed(() => [
'input',
@ -67,11 +68,15 @@ defineExpose({
v-bind="{ ...$attrs, ...inputBindings }"
:class="inputClasses"
:disabled="disabled || undefined"
:aria-invalid="error ? true : undefined"
:aria-describedby="errorId"
@input="handleInput"
>
<p
v-if="error"
:id="errorId"
class="help is-danger"
role="alert"
>
{{ error }}
</p>

View File

@ -27,6 +27,7 @@ defineOptions({inheritAttrs: false})
const fallbackId = useId()
const selectId = computed(() => props.id ?? fallbackId)
const errorId = computed(() => props.error ? `${selectId.value}-error` : undefined)
const wrapperClasses = computed(() => [
'select',
@ -70,6 +71,8 @@ function handleChange(event: Event) {
:id="selectId"
v-bind="{ ...$attrs, ...selectBindings }"
:disabled="disabled || undefined"
:aria-invalid="error ? true : undefined"
:aria-describedby="errorId"
@change="handleChange"
>
<template v-if="normalizedOptions">
@ -87,7 +90,9 @@ function handleChange(event: Event) {
</div>
<p
v-if="error"
:id="errorId"
class="help is-danger"
role="alert"
>
{{ error }}
</p>