fix(pagination): bound controls render as aria-hidden spans — address @leonievoss

<a aria-disabled="true"> is the documented pattern but screen readers
still announce "Previous, link, disabled" on pagination bounds — noise
users don't need because the disabled state is purely visual. Switching
to <span aria-hidden="true"> removes the bound control from the AT tree
entirely (Leonie's recommendation). Visual parity preserved via a
disabledBase Tailwind class (same layout + cursor-not-allowed + opacity-40).

Tests updated: "disabled prev/next" assertions now check for aria-hidden
and no href — the active-state href/aria-current assertions are
unchanged. (#316)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-24 10:52:13 +02:00
committed by marcel
parent 8fa061187e
commit 18b88672ec
2 changed files with 50 additions and 26 deletions

View File

@@ -33,12 +33,14 @@ describe('Pagination', () => {
await expect.element(prev).toHaveAttribute('href', '/documents?page=3');
});
it('disables prev on page 0 (no href, aria-disabled="true")', async () => {
it('renders disabled prev as an aria-hidden non-link so screen readers skip it', async () => {
render(Pagination, { page: 0, totalPages: 3, makeHref });
const prev = page.getByTestId('pagination-prev');
await expect.element(prev).toHaveAttribute('aria-disabled', 'true');
// Not a link — no href, no role=link
await expect.element(prev).not.toHaveAttribute('href');
// Hidden from assistive tech — AT shouldn't read "Previous, link, disabled"
await expect.element(prev).toHaveAttribute('aria-hidden', 'true');
});
it('renders next as a link pointing at page + 1 when not on last page', async () => {
@@ -48,12 +50,12 @@ describe('Pagination', () => {
await expect.element(next).toHaveAttribute('href', '/documents?page=1');
});
it('disables next on the last page (no href, aria-disabled="true")', async () => {
it('renders disabled next as an aria-hidden non-link on the last page', async () => {
render(Pagination, { page: 2, totalPages: 3, makeHref });
const next = page.getByTestId('pagination-next');
await expect.element(next).toHaveAttribute('aria-disabled', 'true');
await expect.element(next).not.toHaveAttribute('href');
await expect.element(next).toHaveAttribute('aria-hidden', 'true');
});
it('calls makeHref with p-1 and p+1', async () => {