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-sort when 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).
Defaults versus configured PrimeVue DataTable Comparison: defaults give a semantic table with generic strings and silent updates; configured tables add names, translated aria strings, meaningful templates and announcements. Defaults versus configured PrimeVue DataTable✗ DefaultsTable without a nameEnglish aria locale strings"No records found"Silent sort and filterTheme focus as shipped✓ Configuredaria-labelledby to the headingTranslated and reviewed stringsFilter-specific empty templateStatus region announcementsVerified in your theme or 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.

DataTable features and what to verify Matrix of features — sorting, column filters (row and menu), selection, row expansion, column toggle, paginator — against labels, keyboard, focus return and announcements. DataTable features and what to verifyLabelsKeyboardFocus returnAnnouncementSortingHeader textEnterN/AAdd statusFilters (row)Check inputsYesN/AAdd countFilters (menu)Check popupsYesVerifyAdd countSelectionLocale stringsSpaceN/AAdd countRow expansionCheck toggler nameEnterN/AOptionalPaginatorLocale ariaYesN/AAdd page status
Every enabled feature adds a checklist.

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
Configuring PrimeVue DataTable Chain: name the table through pass-through; translate aria locale strings; write empty and loading templates; wire sort, filter and page events to the status region; verify theme focus. Configuring PrimeVue DataTablePass-throughnamept.tablearia-labelledbyAria stringstranslated, reviewedEmpty andloadingmeaningful textStatussort, filter, pagemessageslocaletemplateseventsFocusverified 3:1
Five steps from defaults to production-ready.

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"
  1. Configure aria locale strings once at app level, reviewed by a native speaker for each language.
  2. Build a wrapper that applies pass-through naming, standard empty and loading templates, and the announcer wiring for @sort, @filter and @page.
  3. Decide which filter display modes are allowed; most teams need row filters on a few columns or a global filter.
  4. If using unstyled mode, add focus, selection and sort indicator styles to the design system before the first release.
  5. Check row expansion and column toggle controls for names and expanded state.
  6. 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.

Permalink to "Related"

← Back to Vue & Nuxt Data Components