The useAnnouncer Composable
Announce dynamic in-page changes — form results, loading states, search updates — to screen readers, with polite and assertive channels.
What's new#
Nuxt 4.4 adds the useAnnouncer composable and a <NuxtAnnouncer> component for announcing dynamic in-page changes to assistive technology — distinct from useRouteAnnouncer, which only covers navigation.
Why you'd care#
Plenty happens without a page change: a form submits, a search returns results, a background save completes. Screen-reader users miss all of it unless you announce it. useAnnouncer gives you a proper, ARIA-live-backed way to do that.
Before#
You wired up your own ARIA live region and pushed text into it by hand:
<template>
<p aria-live="polite" class="sr-only">{{ liveMessage }}</p>
</template>
<script setup lang="ts">
const liveMessage = ref('')
async function submit() {
await $fetch('/api/contact', { method: 'POST', body: form })
liveMessage.value = 'Message sent successfully'
}
</script>
Every component reinvented the same region and its quirks.
After#
Mount the announcer once, then call polite / assertive anywhere:
<template>
<NuxtAnnouncer />
<NuxtRouteAnnouncer />
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>
<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>
Do it yourself#
- Add
<NuxtAnnouncer />toapp.vuealongside<NuxtRouteAnnouncer />. - In a form component, grab
const { polite, assertive } = useAnnouncer(). - On success call
polite(...); on error callassertive(...). - Turn on a screen reader (VoiceOver on macOS: ⌘+F5) and submit the form.
- Confirm success is announced calmly and errors interrupt immediately.
Gotchas#
politewaits for the reader to finish;assertiveinterrupts. Reserveassertivefor genuine errors — overusing it is hostile to screen-reader users.- You don't need it everywhere. If an interaction moves focus to new content, that already announces itself.
useAnnounceris for changes with no matching focus change.
Recap#
useAnnouncer (polite/assertive) plus <NuxtAnnouncer> announce dynamic content changes to assistive tech. Reach for it when content updates without a focus move.