Semantic Accessible Web

combining Semantic HTML and WAI-ARIA APG

Pixu

Emiliano Pisu

Sensei & Co-Host
@ Dev Dojo IT

pixu1980@linkedin linkedin.com/in/pixu1980
pixu1980@github github.com/pixu1980
pixu1980@codepen codepen.io/pixu1980
devdojo@linkedin linkedin.com/company/dev-dojo-it/
devdojo@youtube youtube.com/@devdojo_it
devdojo@twitch twitch.tv/devdojo_it
devdojo@telegram @devdojo_it

Accessibility is not an optional feature, it's a fundamental digital right for all users.

~15-20% of the global population has permanent or temporary disability: 1 person out to 5, which means 1.64B people

This involves

  • Visual impairments
  • Motor disabilities
  • Hearing loss
  • Cognitive limitations
  • Temporary or situational limitations
  • Environmental access challenges
Let's dive in
Let's dive in Let's dive in Let's dive in Let's dive in Let's dive in

What is WAI-ARIA?

Web Accessibility Initiative

Accessible Rich Internet Applications

A set of guidelines (eg. HTML attributes role and aria-*) to make digital products accessible to people who rely on assistive technologies

What are ARIA APG?

Authoring Practices Guide

A set of guidelines related to the implementation of common design patterns and widgets (eg. Accordion, Breadcrumb, Carousel, Dialog, Landmarks ...)

WAI-ARIA Examples

Accessible Pattern: Alert

This will be announced instantly by screen readers, taking precedence above the rest.


      <div role="alert">
        Network error. Please try again.
      </div>
    

Accessible Pattern: aria-live

Perfect for subtle live updates (chat messages, notifications, video subtitles).


      <div aria-live="polite">
        New message...
      </div>
    

Accessible Pattern: skip link

Allows keyboard users to bypass nav elements, straight to the point.


      <a href="#main" class="skip-link">
        Skip to content
      </a>
      <main id="main">
        ...
      </main>
    

What is Semantic HTML?

As the word may suggest it adds semantic meanings to HTML elements. Which also translates in better readability and maintainability.

A long set of HTML elements which provide the proper semantic meanings to user agents and screen readers

Elements such as <div></div> or <span></span> are often used as a general-purpose element to create headers, footers, menus, articles and web contents in general.

An example?

Many web-based software contain HTML code like the following to indicate the different areas. This, except css classes added to the elements, tells nothing to browsers and screen readers about the content.

    
      <div class="header"></div>
      <div class="nav"></div>
      <div class="main"></div>
      <div class="sidebar"></div>
      <div class="footer"></div>
    
  

Let's add some semantics??

Introducing new elements that tells user agents as well as screen readers or search engines exactly what the element itself does and what kind of content should contain.

These specs allow HTML to present and use web contents in a wide variety of contexts that the author might not have considered.

SEO, Google News, Accelerated Mobile Pages (AMP) and all the other scraping and crawling methods are the players involved here too.

Semantic HTML Layout

The following is just an example of a Semantic HTML layout structure, an example of how semantics helps to design, develop and read a web content from the right perspective

      
        <header>header</header>
        <nav>nav</nav>
        <main>
          main
          <section>section</section>
          <article>article</article>
        </main>
        <aside>aside</aside>
        <footer>footer</footer>
      
    

A <header> element represents
the principal interaction part of a web content

NOTE: When used inside an article element
represents its principal interaction part

A <header> typically contains:

  • brand/logo
  • a set of navigation links
  • user menu/profile

A <nav> represents global or partial navigation links

NOTE: There can be multiple nav elements on a page with different purposes and destinations

A <nav> typically is:

  • mostly intended for major block of navigation links
  • not for containing all the navigation links of the content

A <footer> element represents the last part for a document or a section. This means you can have multiple footer in one HTML document

NOTE: When used inside an article element
represents its last interaction part

A <footer> typically contains:

  • related links
  • back to top links
  • contact information
  • copyright/author information

An <aside> element defines some content aside from the content it is placed in, its content should be indirectly related to the surrounding content

An <aside> typically contains:

  • Related articles or links
  • Author information or bios
  • Advertisements
  • Widgets (e.g., search, recent posts)
  • Navigation that relates to the current page or section

The <main> element is used to designate
the primary content area of a web page.

NOTE: Ensure there is only one main element per page

The <main> is intended to improve accessibility and document structure by clearly indicating the subject matter of the page.

The <main> typically excludes content that repeats across multiple pages, such as: headers, navs, sidebars, footers.

A <section> element represents a thematic grouping of content, usually with an heading, which is part of a larger document

A <section> typically contains:

  • chapters/summary
  • introduction
  • a group of news/cards
  • contacts info
  • tabbed panels/steps in a process

A <article> element represents a self-contained, reusable piece of content that can stand alone or be distributed independently (picture Google News)

A <article> typically contains:

  • product card
  • advertising
  • news/magazine article
  • user comment
  • blog/forum post

What about nesting Articles and Sections? Is that possible?

Let's explore some examples!

section-with-nested-articles.html
      
        <section>
          <h1>Latest News</h1>
          <article>
              <h2>Headline 1</h2>
              <p>Content of the first article.</p>
          </article>
          <article>
              <h2>Headline 2</h2>
              <p>Content of the second article.</p>
          </article>
        </section>
      
    
article-with-nested-sections.html
      
        <article>
          <h1>Understanding Flexbox</h1>
          <section>
              <h2>Introduction</h2>
              <p>Flexbox is a layout model...</p>
          </section>
          <section>
              <h2>Examples</h2>
              <p>
                Here are some common use-cases
                for Flexbox.
              </p>
          </section>
        </article>
      
    
article-with-nested-articles.html
      
        <article>
          <h1>Blog Post Title</h1>
          <p>Content of the blog post.</p>
          <article>
              <h2>Comment 1</h2>
              <p>This is a comment.</p>
          </article>
          <article>
              <h2>Comment 2</h2>
              <p>This is another comment.</p>
          </article>
        </article>
      
    
section-with-nested-sections.html
      
        <section>
          <h1>Chapter 1</h1>
          <section>
              <h2>Section 1.1</h2>
              <p>Details of section 1.1</p>
          </section>
          <section>
              <h2>Section 1.2</h2>
              <p>Details of section 1.2</p>
          </section>
        </section>
      
    

Can we use the <article> and <section> definitions to decide how to nest them?

Nope!

The HTML specs does not place any restrictions on the table about how these elements can be nested. Which means all of the above examples are valid and semantically correct, so easy!

Typographic Semantic Elements

from <h1></h1> to <h6></h6>: Represent headings (title, subtitles, and so on...) for their container headings.html
        
          <h1>Heading 1</h1>
          <h2>Heading 2</h2>
          <h3>Heading 3</h3>
          <h4>Heading 4</h4>
          <h5>Heading 5</h5>
          <h6>Heading 6</h6>
        
      

Heading 1

Heading 2

Heading 3

Heading 4

Heading 5
Heading 6
<hgroup></hgroup>: Represents the heading stack of a content, which consists of all the h1–h6 element children of the hgroup element hgroup.html
      
        <hgroup>
          <h1>
            Understanding the Web
          </h1>
          <h2>
            The Evolution of HTML
          </h2>
        </hgroup>
      
    

Understanding the Web

The Evolution of HTML

<p></p>: Represents a paragraph of text element paragraph.html
      
        <p>
          Curabitur blandit tempus porttitor.
          Sed posuere consectetur est at lobortis.
        </p>
      
    

Curabitur blandit tempus porttitor. Sed posuere consectetur est at lobortis.

<blockquote></blockquote>: Represents a block of text quoted from an external source blockquote.html
        
          <blockquote>
            This is an example of a blockquote.
          </blockquote>
        
      
This is an example of a blockquote.
<q></q>: Represents a short inline quotation quote.html
      
        The author stated:
        <q>
          I'm happy to announce the next book for the upcoming year!
        </q>
      
    
The author stated: I'm happy to announce the next book for the upcoming year!
<cite></cite>: Used to cite the title of a work or the reference of a source cite.html
        
          <cite>The Great Gatsby</cite>
        
      
The Great Gatsby

<strong></strong>: Indicates strong importance,
typically rendered in bold.

strong.html
      
        <strong>
          This is a bold text
        </strong>
      
    
This is a bold text

NOTE: Don't use <b> elements because they don't add any semantic meaning

<em></em>: Indicates emphasis, usually rendered in italics.

emphasis.html
      
        <em>
          This is an italic emphasized text
        </em>
      
    
This is an italic emphasized text

NOTE: Don't use <i> elements because they don't add any semantic meaning

<mark></mark>: Highlights text to draw attention to it

mark.html
      
        <span>
        Remember to
          <mark>
            check this section
          </mark>
        </span>
      
    
Remember to check this section

<small></small>: Represents text of lesser importance, often rendered in smaller font

small.html
        
          <p>
            This is a paragraph with some text
            containing a smaller description
            <br />
            <small>
              (this is the smaller description)
            </small>
          </p>
        
      

This is a paragraph with some text containing a smaller description
(this is the smaller description)

<time></time>: Specifies a date or time in a machine-readable format

abbr.html
      
        <time datetime="2025-01-21">
          January 21, 2025
        </time>
      
    

<kdb></kdb>: Represents user input, such as keyboard or voice commands

kdb.html
        
          Press <kbd>Ctrl</kbd> + <kbd>S</kbd> to save.
        
      

Press Ctrl + S to save.

<abbr></abbr>: Represents an abbreviation or acronym, often with a title attribute for the full term which the user can see hovering the abbr


<dfn></dfn>: Highlights a term being defined

abbr-and-dfn.html
        
          <p>
            This text contains an abbreviation of 
            <abbr title="HyperText Markup Language">
              HTML
            </abbr>
          </p>
          <p>
            <dfn>HTML</dfn> stands for HyperText Markup Language.
          </p>
        
      

This text contains an abbreviation of HTML

HTML stands for HyperText Markup Language.

<ins></ins>: Represents text that has been inserted into a document. The datetime attribute can be used to specify the date and time of the insertion.


<del></del>: Represents text that has been deleted from a document. The datetime attribute can also be used here to specify when the text was removed.

ins-and-del.html
        
          <p>
            The price is 
            <del datetime="2025-01-15">$50</del>
            <ins datetime="2025-01-16">$40</ins>
          </p>
        
      

The price is $50 $40

<sub></sub>: Represents text that should be
displayed as subscript.


<sup></sup>: Represents text that should be
displayed as superscript.

sub-and-sup.html
        
          water = H2O
          
y = x2
water = H2O
y = x2

Non semantic Typography Elements

  • <b></b>: Renders text in bold without adding semantic meaning
  • <i></i>: Renders text in italics without adding semantic meaning
  • <u></u>: Renders text with an underline without adding semantic meaning
  • <s></s>: Represents text with a strikethrough without adding semantic meaning

Embedded Elements (media)

With HTML5 specifications released in 2014 semantics came into play introducing new elements that tells devs and browsers, as well as screen readers or search engines exactly what the element itself does and what kind of content should contain.

<audio></audio>: Embeds audio content

audio.html
        
          <audio
            controls>
            <source
              src="song.mp3"
              type="audio/mpeg">
            Your browser does not support the audio element.
          </audio>
        
      

Music by JT WAYNE from Pixabay

<video></video>: Embeds video content

video.html
        
          <video
            controls 
            width="640"
            height="360"
            poster="poster.jpg">
            <source
              src="video.mp4"
              type="video/mp4">
            Your browser does not support the video element.
          </video>
        
      

<figure></figure>: Groups self-contained content with an optional caption

figure.html
        
          <figure>
            <img
              src="mountains.jpg"
              alt="Scenic view of mountains">
            <figcaption>
              A scenic view of snowy mountains during sunset
            </figcaption>
          </figure>
        
      
Scenic view of mountains
A scenic view of snowy mountains during sunset.

User Input Elements

<button></button>: Represents a clickable button for user interaction. Used for actions like submitting forms, toggling states, or triggering JavaScript events.

<input />: Represents a field for user input. A versatile element with various types of data.

<textarea></textarea>: Represents a multi-line text input field. Used for longer text inputs, such as comments or descriptions.

<select></select>: Represents a dropdown menu for selecting options. Used for single or multiple selections.


<option></option>: Represents an item in a dropdown list. Defines individual choices within a <select>.


<optgroup></optgroup>: Represents a grouping of related <option> elements within a <select> dropdown. Semantics: Used to create logical groups of options, making large lists easier to navigate and understand for users.

<label></label>: Describes a form <input> or <select> or <textarea>, linking it to its corresponding field. Enhances form accessibility by associating a description with an input.

<details></details>: Represents a disclosure widget, allowing users to expand and collapse content. Used for hiding additional information until needed.


<summary></summary>: Represents a summary or label for the <details> element. The clickable part of a disclosure widget.

<form></form>: Is a container for collecting user input and submitting it to a server or handling it via client-side JavaScript. It represents a section of a document intended for interactive controls to submit data.


<fieldset></fieldset>: Groups related form elements visually and semantically. Used to organize complex forms.


<legend></legend>: Provides a caption for the <fieldset> element. Improves accessibility and form clarity.

Here's a full form example

          
            <form action="/" method="POST">
              <fieldset>
                <legend>Authentication</legend>
                <label>
                  Username
                  <input
                    name="username"
                    type="text"
                    placeholder="Insert your username"
                    required
                  />
                </label>
                <label>
                  Password
                  <input
                    name="password"
                    type="password"
                    placeholder="Insert your password"
                    required
                  />
                </label>
              </fieldset>
              <details>
                <summary>Click here to open optional fields</summary>
                <fieldset>
                  <legend>Optional fields</legend>
                  <label>
                    Diet
                    <select name="food">
                      <optgroup label="Fruits">
                        <option value="apple">Apple</option>
                        <option value="banana">Banana</option>
                        <option value="orange">Orange</option>
                      </optgroup>
                      <optgroup label="Vegetables" disabled>
                        <option value="carrot">Carrot</option>
                        <option value="broccoli">Broccoli</option>
                        <option value="spinach">Spinach</option>
                      </optgroup>
                      <optgroup label="Meat">
                        <option value="cow">Cow</option>
                        <option value="pork">Pork</option>
                        <option value="chicken">Chicken</option>
                      </optgroup>
                    </select>
                  </label>
                  <label>
                    Connection
                    <select name="connection">
                      <option value="5G">5G</option>
                      <option value="4G">4G</option>
                      <option value="3G">
                        3G (Grazia, Graziella e... Giorgio)
                      </option>
                    </select>
                  </label>
                  <label>
                    Describe yourself
                    <textarea
                      name="description"
                      placeholder="Describe yourself here..."
                    ></textarea>
                  </label>
                </fieldset>
              </details>
              <label>
                <input name="remember-me" type="checkbox" /> Remember me
              </label>
              <button type="submit">Login</button>
            </form>
          
        
Authentication
Click here to open optional fields
Optional fields

<dialog></dialog>: Represents a dialog box or modal window. Used for popups, alerts, or forms requiring focused user interaction.

        
          <button id="openDialog">Open Dialog</button>
          <dialog id="myDialog">
            <h2>Dialog Title</h2>
            <p>
              This is a modal dialog. You can use it for alerts, confirmations, or
              any other interaction.
            </p>
            <form method="dialog">
              <button type="submit" class="close-btn">Close</button>
            </form>
          </dialog>
          <script>
            const dialog = document.getElementById('myDialog');
            const openButton = document.getElementById('openDialog');
  
            openButton.addEventListener('click', () => {
              dialog.showModal(); // Open the dialog as a modal
            });
  
            dialog.addEventListener('close', () => {
              console.log('Dialog closed with:', dialog.returnValue);
            });
          </script>
        
      

Dialog Title

This is a modal dialog. You can use it for alerts, confirmations, or any other interaction.

Semantics enhances accessibility, searchability, SEO, localization, and interoperability.

So, if there's a native element which does what you need: please don't reinvent the wheel, try to find a way to use and style native semantic HTML elements.

Accessibility Tooling

  • axe DevTools
  • Lighthouse (Chrome)
  • NVDA (Windows)
  • VoiceOver (macOS/iOS)
  • Orca (Linux)

Accessibility Checklist

  • Use semantic HTML whenever possible
  • Use WAI-ARIA only when absolutely necessary
  • Check and ensure the proper focus and reading order
  • Test Keyboard-only navigation (TAB, ENTER, ESC)
  • Whenever possible do human tests

Final Thoughts

Accessibility is not optional. It reflects quality, responsibility and respect.

Every technical decision is also an ethical decision. Writing accessible code makes the web better... for everyone.

Accessibility is a continuous work in progress, keep yourself up to date: make learning a habit!

An Awesome CSS Link a Day

Pixu.dev

Slides

Slides on Github Pages

Slides Repo

Slides Repo on Github
© 1987-2025 - Warner Bros. Entertainment Inc.
Pixu

Grazie ❤️!

Dev Dojo IT Logo