Skip to content

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.

AttributePurposeUsage Rules
roleDefines the role of an elementMust not duplicate the implicit role of a native HTML element
aria-labelSpecifies the accessible name of an elementUsed for elements without a visible label
aria-labelledbySpecifies a name using text from another elementUsed when a visible label exists, referencing that element's id
aria-describedbyAssociates additional description with an elementUsed 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 role must not be redundantly assigned to native semantic elements such as <button>, <nav>, and <header>.
  • aria-label and aria-labelledby must not be used simultaneously. aria-labelledby takes precedence.

19.2.2. Live Regions

Live regions are used to notify assistive technologies of dynamically changing content.

AttributeValueBehavior
aria-livepoliteAnnounces changes after the user's current task is complete
aria-liveassertiveAnnounces changes immediately. Used only for urgent notifications
aria-atomictrue / falseDetermines 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" and aria-modal="true" must be specified.
  • aria-labelledby must 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.

AttributePurposeApplicable To
aria-requiredIndicates a required input fieldRequired input fields
aria-invalidIndicates validation failure stateFields that have failed validation
aria-errormessageAssociates an error message elementFields 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. The for attribute of <label> must match the id attribute of <input>.
  • placeholder must not be used as a substitute for a label. placeholder should be used only as supplementary hint text.
  • aria-invalid must be set to true only after validation has been executed. It must not be set in the initial state.
  • aria-errormessage must have a valid reference target only when aria-invalid="true".

TIENIPIA QUALIFIED STANDARD