ARIA Attributes
19.2.1. Basic ARIA Attributes
ARIA (Accessible Rich Internet Applications) attributes are used when the meaning cannot be conveyed by native HTML elements alone. ARIA attributes must not be added when native HTML semantics are sufficient.
| Attribute | Purpose | Usage Rules |
|---|---|---|
role | Defines the role of an element | Must not duplicate the implicit role of a native HTML element |
aria-label | Specifies the accessible name of an element | Used for elements without a visible label |
aria-labelledby | Specifies a name using text from another element | Used when a visible label exists, referencing that element's id |
aria-describedby | Associates additional description with an element | Used to link help text, hint text, etc. |
vue
<template>
<!-- aria-label: Icon button without visible text -->
<button aria-label="Search" @click="handleSearch">
<SearchIcon />
</button>
<!-- aria-labelledby: References a visible label -->
<h2 id="section-title">User List</h2>
<table aria-labelledby="section-title">
<!-- Table content -->
</table>
<!-- aria-describedby: Associates additional description -->
<input
id="password"
type="password"
aria-describedby="password-hint"
/>
<p id="password-hint">Must be at least 8 characters, including letters and numbers.</p>
</template>- The same semantic
rolemust not be redundantly assigned to native semantic elements such as<button>,<nav>, and<header>. aria-labelandaria-labelledbymust not be used simultaneously.aria-labelledbytakes precedence.
19.2.2. Live Regions
Live regions are used to notify assistive technologies of dynamically changing content.
| Attribute | Value | Behavior |
|---|---|---|
aria-live | polite | Announces changes after the user's current task is complete |
aria-live | assertive | Announces changes immediately. Used only for urgent notifications |
aria-atomic | true / false | Determines whether to re-read the entire region or only the changed part |
vue
<script setup lang="ts">
import { ref } from 'vue'
const statusMessage = ref('')
const errorMessage = ref('')
async function handleSave() {
try {
await saveData()
statusMessage.value = 'Save completed successfully.'
} catch {
errorMessage.value = 'Save failed. Please try again.'
}
}
</script>
<template>
<!-- polite: General status message -->
<div aria-live="polite" aria-atomic="true">
{{ statusMessage }}
</div>
<!-- assertive: Urgent error message -->
<div aria-live="assertive" aria-atomic="true" role="alert">
{{ errorMessage }}
</div>
</template>aria-live="assertive"must be used only for urgent cases such as error notifications and session expiration warnings.- For general status updates (loading complete, data refresh, etc.),
aria-live="polite"must be used. - Live region elements must exist in the DOM at page load time. Assistive technologies may not recognize dynamically created live regions.
19.2.3. Modals/Dialogs
Modal dialogs must comply with the following ARIA attributes and focus management rules.
vue
<script setup lang="ts">
import { ref, nextTick } from 'vue'
const isOpen = ref(false)
const dialogRef = ref<HTMLElement | null>(null)
let previousFocus: HTMLElement | null = null
async function openModal() {
previousFocus = document.activeElement as HTMLElement
isOpen.value = true
await nextTick()
dialogRef.value?.focus()
}
function closeModal() {
isOpen.value = false
previousFocus?.focus()
}
</script>
<template>
<div
v-if="isOpen"
ref="dialogRef"
role="dialog"
aria-modal="true"
aria-labelledby="dialog-title"
tabindex="-1"
>
<h2 id="dialog-title">Confirmation</h2>
<p>Do you want to save the changes?</p>
<button @click="closeModal">Cancel</button>
<button @click="handleConfirm">Save</button>
</div>
</template>role="dialog"andaria-modal="true"must be specified.aria-labelledbymust reference the dialog's title element.- When a modal opens, focus must be moved to the first focusable element within the modal or to the dialog itself.
- When a modal closes, focus must be restored to the element that was focused before the modal was opened.
- Focus trapping must be implemented to prevent focus from moving outside the modal while it is open.
19.2.4. Form Accessibility
Form elements must use the following ARIA attributes to ensure accessibility.
| Attribute | Purpose | Applicable To |
|---|---|---|
aria-required | Indicates a required input field | Required input fields |
aria-invalid | Indicates validation failure state | Fields that have failed validation |
aria-errormessage | Associates an error message element | Fields with aria-invalid="true" |
vue
<template>
<form @submit.prevent="handleSubmit">
<label for="user-email">Email</label>
<input
id="user-email"
v-model="form.email"
type="email"
aria-required="true"
:aria-invalid="!!errors.email"
:aria-errormessage="errors.email ? 'email-error' : undefined"
@blur="validateField('email')"
/>
<p
v-if="errors.email"
id="email-error"
role="alert"
>
{{ errors.email }}
</p>
</form>
</template>- Every input field must have an associated
<label>element. Theforattribute of<label>must match theidattribute of<input>. placeholdermust not be used as a substitute for a label.placeholdershould be used only as supplementary hint text.aria-invalidmust be set totrueonly after validation has been executed. It must not be set in the initial state.aria-errormessagemust have a valid reference target only whenaria-invalid="true".