Tailwind CSS Academy · Les

ARIA-attributen en schermlezers

Combineer de sr-only-utility van Tailwind met aria-*-HTML-attributen om schermlezers context te bieden zonder de visuele layout te beïnvloeden.

Les 3 van 413 stappen

ARIA-attributen en schermlezers is een gratis Tailwind CSS Academy-les op CoddyKit. Dit is les 3 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Tailwind CSS Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Tailwind CSS Academy bevat in totaal 4 lessen.

Hoe schermlezers werken

Schermlezers zijn ondersteunende software die visuele inhoud omzet in gesproken tekst of braille-uitvoer. Ze lezen de toegankelijkheidsstructuur — een gestructureerde weergave van de pagina die is afgeleid van de DOM — in plaats van de visuele lay-out. De toegankelijkheidsstructuur bevat rollen, namen, statussen en eigenschappen van elementen. De visuele klassen van Tailwind beïnvloeden de DOM, maar om correct met schermlezers te communiceren heb je ook de juiste HTML-semantiek en ARIA-attributen nodig.

Eerst semantische HTML

Gebruik voordat je ARIA toepast semantische HTML-elementen: deze hebben ingebouwde toegankelijkheidsrollen die schermlezers zonder extra attributen begrijpen. Een <button> wordt aangekondigd als 'knop', een <h1> als kopniveau 1 en een <nav> als navigatieoriëntatiepunt. Als je overal <div> voor gebruikt, moet je dit compenseren door ARIA toe te voegen. De eerste regel van ARIA is: gebruik semantische HTML als een native element de semantiek al biedt.

<!-- BAD: div-based — requires ARIA to make accessible -->
<div class='flex items-center gap-2 cursor-pointer' onclick='handleClick()'>
  <span class='text-sm'>Submit</span>
</div>

<!-- GOOD: semantic button — accessible by default -->
<button
  type='submit'
  class='flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg'
>
  Submit
</button>

<!-- BAD: no landmark semantics -->
<div class='flex gap-4'>Nav links...</div>

<!-- GOOD: nav landmark -->
<nav class='flex gap-4' aria-label='Main navigation'>Nav links...</nav>

Het hulpprogramma sr-only van Tailwind

De klasse sr-only van Tailwind verbergt inhoud visueel, maar houdt deze toegankelijk voor schermlezers. De klasse gebruikt een specifieke CSS-techniek: een clip van 1×1 pixel met verborgen overflow en absolute positionering. Hierdoor wordt het element uit de visuele lay-out verwijderd, maar blijft het in de toegankelijkheidsstructuur staan. Gebruik sr-only voor labels, beschrijvingen en context die schermlezers nodig hebben, maar die ziende gebruikers uit visuele aanwijzingen halen.

/* What .sr-only does */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

<!-- Usage: icon buttons need visible labels for screen readers -->
<button class='p-2 rounded-lg hover:bg-gray-100'>
  <XMarkIcon class='h-5 w-5 text-gray-700' />
  <span class='sr-only'>Close dialog</span>
</button>

ARIA-labels en beschrijvingen

aria-label biedt een toegankelijke naam wanneer er geen zichtbaar tekstlabel is. Gebruik dit voor knoppen met alleen een pictogram of voor elementen waarvan het visuele label niet voldoende is. aria-labelledby verwijst naar de ID van een zichtbaar element dat als toegankelijke naam wordt gebruikt. aria-describedby verwijst naar een element dat aanvullende context biedt — zoals een foutmelding of een hint onder een formulierveld — die na het label van het element wordt aangekondigd.

<!-- aria-label for icon-only button -->
<button aria-label='Open notifications'
  class='p-2 rounded-lg hover:bg-gray-100'>
  <BellIcon class='h-5 w-5' />
</button>

<!-- aria-labelledby references visible heading -->
<section aria-labelledby='pricing-heading'>
  <h2 id='pricing-heading' class='text-2xl font-bold'>Pricing</h2>
  {/* screen reader: 'Pricing, region' */}
</section>

<!-- aria-describedby links to help text -->
<div>
  <label for='email'>Email</label>
  <input id='email' type='email' aria-describedby='email-hint' />
  <p id='email-hint' class='text-sm text-gray-500 mt-1'>
    We will never share your email.
  </p>
</div>

Dynamische ARIA-regio's

Dynamische ARIA-regio's kondigen wijzigingen in dynamische inhoud aan schermlezers aan zonder de focus te verplaatsen. Gebruik aria-live='polite' voor niet-dringende updates (zoals het laden van zoekresultaten) en aria-live='assertive' voor dringende aankondigingen (zoals foutmeldingen). De inhoud van de dynamische regio wordt aangekondigd wanneer deze verandert. Tailwind-klassen bepalen de visuele stijl van de container; het toegankelijkheidsgedrag komt volledig van het ARIA-attribuut.

<!-- Polite: announced after current announcement finishes -->
<div
  aria-live='polite'
  aria-atomic='true'
  class='sr-only'  {/* screen reader only — no visual display */}
>
  {searchStatus} {/* e.g., 'Loading results...' or '12 results found' */}
</div>

<!-- Assertive: interrupts current announcement -->
<div
  aria-live='assertive'
  role='alert'
  class='fixed top-4 right-4 bg-red-50 border border-red-200 p-4 rounded-lg'
>
  {errorMessage}
</div>

ARIA-rollen voor aangepaste componenten

Wanneer je aangepaste interactieve componenten bouwt met niet-semantische HTML (zoals een combobox op basis van een div of een aangepaste schakelaar), voeg je de juiste ARIA-rol toe om duidelijk te maken wat het element is. Veelgebruikte rollen zijn button, checkbox, combobox, listbox, option, tab, tabpanel, dialog en alert. De rol bepaalt het impliciete toetsenbordcontract en welke statussen betekenisvol zijn voor dat elementtype.

<!-- Custom toggle switch -->
<div
  role='switch'
  aria-checked={enabled}
  tabIndex={0}
  onKeyDown={(e) => e.key === 'Enter' && toggle()}
  onClick={toggle}
  class={cn(
    'relative inline-flex h-6 w-11 items-center rounded-full cursor-pointer',
    'focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2',
    enabled ? 'bg-blue-600' : 'bg-gray-300'
  )}
>
  <span class='sr-only'>{enabled ? 'Enabled' : 'Disabled'}</span>
  <span class={cn('inline-block h-4 w-4 rounded-full bg-white transition-transform',
    enabled ? 'translate-x-6' : 'translate-x-1'
  )} />
</div>

ARIA-statussen en -eigenschappen

ARIA-statussen (aria-checked, aria-expanded, aria-selected, aria-disabled) geven de huidige interactieve status van een element door. Werk deze programmatisch bij zodat de toegankelijkheidsstructuur synchroon blijft met de visuele status. Als een sectie met extra inhoud wordt uitgevouwen, stel je aria-expanded='true' in op het activerende element. Als een item in een lijst is geselecteerd, stel je aria-selected='true' in. Schermlezers kondigen deze statuswijzigingen aan terwijl de gebruiker interactie heeft met de pagina.

function AccordionItem({ title, content }) {
  const [expanded, setExpanded] = useState(false);
  const contentId = 'accordion-content-' + title.replace(/\s/g, '-');

  return (
    <div class='border-b border-gray-200'>
      <button
        onClick={() => setExpanded(!expanded)}
        aria-expanded={expanded}
        aria-controls={contentId}
        class='flex w-full justify-between items-center py-4 text-left'
      >
        {title}
        <ChevronDownIcon class={cn('h-5 w-5 transition-transform', expanded && 'rotate-180')} />
      </button>

      <div
        id={contentId}
        hidden={!expanded}
        class='pb-4 text-gray-600 text-sm leading-relaxed'
      >
        {content}
      </div>
    </div>
  );
}

Decoratieve inhoud verbergen voor schermlezers

Niet alle visuele inhoud moet door schermlezers worden aangekondigd. Decoratieve afbeeldingen, dubbele pictogrammen (wanneer tekst de betekenis al overbrengt) en lay-outelementen moeten worden verborgen in de toegankelijkheidsstructuur. Gebruik aria-hidden='true' om een element uit de structuur te verwijderen zonder het visueel te verbergen. Voeg aria-hidden='true' nooit toe aan elementen die focusbare elementen bevatten of daarmee verband houden.

<!-- Decorative image: hide from screen reader -->
<img
  src='/decorative-pattern.svg'
  alt=''  {/* empty alt = decorative */}
  class='absolute inset-0 opacity-5'
  aria-hidden='true'
/>

<!-- Icon alongside text: icon is decorative -->
<button class='flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg'>
  <SaveIcon class='h-4 w-4' aria-hidden='true' />
  Save Changes  {/* text label is sufficient */}
</button>

<!-- Spinner: decorative, but announce loading state differently -->
<button disabled aria-busy='true'>
  <span aria-hidden='true' class='animate-spin'>...</span>
  <span class='sr-only'>Saving...</span>
</button>

Oriëntatiepunten voor navigatie met schermlezers

Oriëntatiepuntrollen maken het mogelijk om rechtstreeks naar belangrijke paginagedeelten te springen. De semantische HTML5-elementen <main>, <nav>, <header>, <footer>, <aside> en <section> (met een naam) maken automatisch oriëntatiepuntregio's. Als je meerdere <nav>-elementen hebt, onderscheid je deze met aria-label, zodat schermlezergebruikers naar de juiste navigatie kunnen gaan.

<body class='min-h-screen flex flex-col'>
  {/* banner landmark */}
  <header class='bg-white border-b border-gray-200'>
    <nav aria-label='Main navigation' class='flex gap-6 px-6 h-16 items-center'>
      {/* nav links */}
    </nav>
  </header>

  <div class='flex flex-1'>
    {/* complementary landmark */}
    <aside class='w-64 border-r border-gray-200' aria-label='Sidebar'>
      <nav aria-label='Section navigation'>{/* sidebar links */}</nav>
    </aside>

    {/* main landmark */}
    <main class='flex-1 p-8'>{/* page content */}</main>
  </div>

  {/* contentinfo landmark */}
  <footer class='bg-gray-50 border-t border-gray-200 py-8'>
    {/* footer content */}
  </footer>
</body>

Visueel verborgen focusaankondigingen

Sommige UI-patronen vereisen aankondigingen voor schermlezers zonder visueel equivalent. Nadat een formulier bijvoorbeeld succesvol is verzonden, kun je de focus verplaatsen naar een kop met sr-only die 'Formulier succesvol verzonden' meldt. Dit is een duidelijke aanpak die schermlezergebruikers informeert zonder de visuele UI te wijzigen. Combineer sr-only met een ref met tabIndex={-1} die programmatisch focus ontvangt.

// After form submit, announce result to screen readers
function SubmitForm() {
  const [submitted, setSubmitted] = useState(false);
  const statusRef = useRef(null);

  const handleSubmit = async (e) => {
    e.preventDefault();
    await submitForm();
    setSubmitted(true);
    // Move focus to the sr-only status message
    statusRef.current?.focus();
  };

  return (
    <form onSubmit={handleSubmit}>
      {submitted && (
        <p
          ref={statusRef}
          tabIndex={-1}
          class='sr-only'
        >
          Your form was submitted successfully. We will be in touch.
        </p>
      )}
      {/* form fields */}
      <button type='submit'>Submit</button>
    </form>
  );
}

Geautomatiseerd testen met schermlezers

Hoewel niets testen met een echte schermlezer vervangt (NVDA op Windows, VoiceOver op macOS/iOS, TalkBack op Android), detecteren geautomatiseerde hulpmiddelen veelvoorkomende problemen. axe-core controleert op ontbrekende ARIA-labels, ongeldig gebruik van rollen en ontoegankelijk kleurcontrast. Integreer het in je CI-pijplijn met jest-axe voor componenttests of axe-playwright voor end-to-endtests.

// jest-axe: test individual React components
import { render } from '@testing-library/react';
import { axe, toHaveNoViolations } from 'jest-axe';

expect.extend(toHaveNoViolations);

test('Button has no accessibility violations', async () => {
  const { container } = render(
    <button class='px-4 py-2 bg-blue-600 text-white rounded'>
      Submit
    </button>
  );
  const results = await axe(container);
  expect(results).toHaveNoViolations();
});

test('Icon button has accessible label', async () => {
  const { container } = render(
    <button aria-label='Close dialog'>
      <XMarkIcon class='h-5 w-5' />
    </button>
  );
  expect(await axe(container)).toHaveNoViolations();
});

Korte controle

Test je begrip van de concepten uit deze les over Tailwind CSS Mastery.

Samenvatting van de les

In deze les heb je geleerd dat sr-only inhoud visueel verbergt, maar toegankelijk houdt voor schermlezers, dat ARIA-labels, -rollen en -statussen aangepaste componenten aanvullen met toegankelijkheidssemantiek en dat aria-live-regio's wijzigingen in dynamische inhoud aankondigen zonder de focus te verplaatsen. Hierna passen we alle toegankelijkheidstechnieken toe om toegankelijke formuliercomponenten te bouwen.

Gratis beginnen

Leer HTML met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
30
Lessen
120

Veelgestelde vragen

Is de les “ARIA-attributen en schermlezers” gratis?

Ja — de volledige tekst van “ARIA-attributen en schermlezers” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus Tailwind CSS Academy wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus Tailwind CSS Academy bevat in totaal 4 lessen.

Wat leer ik in “ARIA-attributen en schermlezers”?

Combineer de sr-only-utility van Tailwind met aria-*-HTML-attributen om schermlezers context te bieden zonder de visuele layout te beïnvloeden. Je oefent met Tailwind CSS Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met Tailwind CSS Academy te beginnen?

Ervaring vooraf is niet nodig. Tailwind CSS Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 3 van 4.

Hoe lang duurt de les “ARIA-attributen en schermlezers”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over Tailwind CSS Academy?

Ja. Elke les over Tailwind CSS Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. Kleurcontrast en leesbare tekst
  2. Focusindicatoren en toetsenbordnavigatie
  3. ARIA-attributen en schermlezers
  4. Toegankelijke formuliercomponenten
← Terug naar Tailwind CSS Academy