One point I haven't seen mentioned yet is that a11y provides obvious business value in that it forces devs to write better and more testable code. I first noticed this when using react-testing-library [1], when refactoring my code to be more easily testable became equivalent to adding a11y features.
Example from a project I worked on: I needed to test that when a button is clicked that the app showed a spinner when loading and then the content when the API call completed successfully. The spinner component was just an SVG with no obvious way to select it without adding a test-id, so instead I refactored the app to use an aria-busy attribute [2] in the container where the content is loading. The test then becomes something like this:
test('shows spinner while loading and content after API call', async () => {
render(<Example />);
userEvent.click(screen.getByRole('button', { name: /load content/i }));
expect(screen.getByRole('main')).toHaveAttribute('aria-busy', 'true');
await waitFor(() => {
expect(screen.getByRole('main')).toHaveAttribute('aria-busy', 'false');
expect(screen.getByText(/content loaded/i)).toBeInTheDocument();
});
});
Example from a project I worked on: I needed to test that when a button is clicked that the app showed a spinner when loading and then the content when the API call completed successfully. The spinner component was just an SVG with no obvious way to select it without adding a test-id, so instead I refactored the app to use an aria-busy attribute [2] in the container where the content is loading. The test then becomes something like this:
[1] https://testing-library.com/docs/queries/about#priority [2] https://developer.mozilla.org/en-US/docs/Web/Accessibility/A...