useAnnouncer

Source
A composable for announcing messages to screen readers.
This composable is available in Nuxt v3.17+.

Description

A composable for announcing dynamic content changes to screen readers. Unlike useRouteAnnouncer which automatically announces route changes, useAnnouncer gives you manual control over what and when to announce.

Use this for in-page updates like form validation, async operations, toast notifications, and live content changes.

Parameters

  • politeness: Sets the default urgency for screen reader announcements: off (disable the announcement), polite (waits for silence), or assertive (interrupts immediately). (default polite)

Properties

message

  • type: Ref<string>
  • description: The current message to announce

politeness

  • type: Ref<'polite' | 'assertive' | 'off'>
  • description: Screen reader announcement urgency level

Methods

set(message, politeness = "polite")

Sets the message to announce with its urgency level.

polite(message)

Sets the message with politeness = "polite". Use for non-urgent updates that can wait for the screen reader to finish its current task.

assertive(message)

Sets the message with politeness = "assertive". Use for urgent updates that should interrupt the screen reader immediately.

Example

app/pages/contact.vue
<script setup lang="ts">
const { polite, assertive } = useAnnouncer()

async function submitForm () {
  try {
    await $fetch('/api/contact', { method: 'POST', body: formData })
    polite('Message sent successfully')
  } catch (error) {
    assertive('Error: Failed to send message')
  }
}
</script>

Use Cases

Form Validation

app/components/LoginForm.vue
<script setup lang="ts">
const { assertive } = useAnnouncer()

function validateForm () {
  const errors = []
  if (!email.value) { errors.push('Email is required') }
  if (!password.value) { errors.push('Password is required') }

  if (errors.length) {
    assertive(`Form has ${errors.length} errors: ${errors.join(', ')}`)
    return false
  }
  return true
}
</script>

Loading States

app/pages/dashboard.vue
<script setup lang="ts">
const { polite } = useAnnouncer()

const { data, status } = await useFetch('/api/data')

watch(status, (newStatus) => {
  if (newStatus === 'pending') {
    polite('Loading data...')
  } else if (newStatus === 'success') {
    polite('Data loaded successfully')
  }
})
</script>

Search Results

app/components/Search.vue
<script setup lang="ts">
const { polite } = useAnnouncer()

const results = ref([])

watch(results, (newResults) => {
  polite(`Found ${newResults.length} results`)
})
</script>
You need to add the <NuxtAnnouncer> component to your app for the announcements to be rendered in the DOM.
For automatic announcements of route/page changes, use useRouteAnnouncer with the <NuxtRouteAnnouncer> component instead.