PrimeVue DataTable Accessibility
Permalink to "PrimeVue DataTable Accessibility"PrimeVue’s DataTable is one of the most feature-complete Vue tables, and PrimeVue documents accessibility for each component: the DataTable renders a semantic table, sortable headers expose aria-sort and are keyboard operable, selection uses checkboxes or radio buttons with labels, and the Paginator has labelled navigation buttons. Like every library, it needs context from you — a name, meaningful messages and announcements of results — and its many features (column filters, row expansion, column toggles) each add controls that need checking.
This guide belongs to Vue & Nuxt data components.
Spec reference
Permalink to "Spec reference"- Table semantics — semantic table markup; header cells with
aria-sortwhen sortable. - Selection — checkbox or radio selection with accessible names derived from locale strings (verify per version).
- Paginator — navigation buttons with labels from the locale (
aria.firstPageLabel,aria.nextPageLabel, etc.). - SC 4.1.2 (A), SC 4.1.3 (AA), SC 2.4.7 (AA) — names, status messages, focus visibility in your theme (PrimeVue themes and unstyled mode).
When to use — and when not to
Permalink to "When to use — and when not to"Use PrimeVue DataTable for feature-rich Vue tables. Enable only the features users need; each feature adds controls and messages to verify.
The misapplication: enabling the “filter display menu” with dozens of matchMode options on every column, which creates many popups whose labels and focus handling all need review, when a simple global filter would have served users better.
Annotated code example
Permalink to "Annotated code example"<template>
<h2 id="inv-h">Invoices</h2>
<DataTable :value="invoices" v-model:selection="selected" dataKey="id"
sortMode="single" removableSort paginator :rows="25"
:pt="{ table: { 'aria-labelledby': 'inv-h' } }" <!-- pass-through to the table element (SC 4.1.2) -->
@sort="onSort" @filter="onFilter" @page="onPage">
<template #empty>No invoices match the current filters.</template>
<template #loading>Loading invoices…</template>
<Column selectionMode="multiple" headerStyle="width: 3rem" />
<Column field="id" header="Invoice" sortable />
<Column field="customer" header="Customer" sortable />
<Column field="amount" header="Amount (EUR)" sortable />
</DataTable>
<p role="status" class="visually-hidden">{{ status }}</p> <!-- SC 4.1.3 -->
</template>
<script setup>
const status = ref('');
const onSort = (e) => status.value = e.sortField ? `Sorted by ${label(e.sortField)}, ${e.sortOrder === 1 ? 'ascending' : 'descending'}` : 'Sort cleared';
const onFilter = (e) => status.value = `${e.filteredValue.length} invoices shown`;
const onPage = (e) => status.value = `Page ${e.page + 1} of ${e.pageCount}`;
</script>
// Translate aria strings used by DataTable and Paginator (verify keys in your version)
app.use(PrimeVue, { locale: { aria: {
selectAll: 'Select all invoices', unselectAll: 'Deselect all invoices',
nextPageLabel: 'Next page', previousPageLabel: 'Previous page',
rowsPerPageLabel: 'Invoices per page',
} } });
Keyboard & AT behaviour
Permalink to "Keyboard & AT behaviour"| Interaction | Expected behaviour | Expected announcement |
|---|---|---|
| Tab to sortable header | Focus | Header and sort state |
| Enter | Sort | aria-sort update; status message |
| Space on row checkbox | Select | Checkbox state; consider a count message |
| Paginator next | Load next page | Button name; “Page 2 of 10” status |
| Filter menu | Opens popup | Popup content and focus moves into it |
Integration context
Permalink to "Integration context"PrimeVue and PrimeNG share concepts, so PrimeNG table accessibility is a useful comparison. Filter UIs follow accessible filtering & faceted search. Announcement wording follows announcing filter result counts with aria-live.
Gotchas
Permalink to "Gotchas"Unstyled mode. In unstyled mode, focus styles are yours entirely; do not ship without them.
Pass-through API. Attributes on the DataTable component may not reach the table element; use the pt API to target it.
Frozen columns and scrollable tables. Scrollable tables split headers and bodies in some configurations; verify header association with a screen reader.
Common mistakes
Permalink to "Common mistakes"- No table name.
- Untranslated aria locale strings.
- Enabling every filter mode on every column.
- No announcements for results.
Version and upgrade notes
Permalink to "Version and upgrade notes"PrimeVue’s theming and pass-through systems changed significantly across major versions (styled versus unstyled modes, design tokens). After upgrades, recheck focus styles, the pt targets for the table name, and aria locale keys.
Worked example
Permalink to "Worked example"A university admin portal used PrimeVue DataTable with menu filters on all twelve columns. A screen reader user struggled with dozens of filter popups whose matchMode dropdowns were unlabelled in the custom theme. The team simplified to a global search plus filters on three key columns, translated the aria locale strings, named the table through pass-through, and added status messages. The table became faster to use for everyone, and the accessibility issues in filter popups disappeared with them.
Adoption checklist for teams
Permalink to "Adoption checklist for teams"- Configure aria locale strings once at app level, reviewed by a native speaker for each language.
- Build a wrapper that applies pass-through naming, standard empty and loading templates, and the announcer wiring for
@sort,@filterand@page. - Decide which filter display modes are allowed; most teams need row filters on a few columns or a global filter.
- If using unstyled mode, add focus, selection and sort indicator styles to the design system before the first release.
- Check row expansion and column toggle controls for names and expanded state.
- Record the configuration in docs so teams do not re-enable discouraged features.
Testing checklist
Permalink to "Testing checklist"Design system notes
Permalink to "Design system notes"Provide a PrimeVue DataTable preset with pass-through naming, locale strings, templates and the announcer. Restrict filter modes to the ones users need, and document why.
FAQ
Permalink to "FAQ"Is PrimeVue DataTable accessible?
PrimeVue documents accessibility for it, and its foundation is good. Your configuration completes it.
How do I set the table's name?
Use the pass-through (pt) API to set aria-labelledby or aria-label on the table element.
Does it announce sorting?
It sets sort state on headers. Add a status message for the result.
What about row expansion?
Check that the toggler button has a meaningful name and aria-expanded, and that expanded content is reachable.
Can I use it in unstyled mode accessibly?
Yes, but you must supply focus, selection and contrast styles.
Should I use lazy mode for server data?
Yes; announce results after each lazy load completes.
Does PrimeVue's Paginator announce page changes?
Its buttons are labelled, but the resulting page is not announced. Announce “Page 2 of 10” from the page event.
How should frozen columns behave for screen readers?
Frozen columns are a visual effect; reading order should remain the column order. Test with table navigation that headers still match cells.
Can I combine PrimeVue's Column Toggle with announcements?
Yes; when users hide or show columns, announce “Customer column hidden” so screen reader users know why it no longer appears.
Related
Permalink to "Related"- Vuetify data table accessibility — the Vuetify equivalent
- PrimeNG table accessibility — the Angular sibling
- Announcing filter result counts — message wording