Semantic Accessible Web
combining Semantic HTML and WAI-ARIA APG
Emiliano Pisu
Sensei & Co-Host
@ Dev Dojo IT
linkedin.com/in/pixu1980
github.com/pixu1980
codepen.io/pixu1980
linkedin.com/company/dev-dojo-it/
youtube.com/@devdojo_it
twitch.tv/devdojo_it
@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
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>
<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>
<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>
<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>
<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
<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>
<h1>
Understanding the Web
</h1>
<h2>
The Evolution of HTML
</h2>
</hgroup>
Understanding the Web
The Evolution of HTML
<p>
Curabitur blandit tempus porttitor.
Sed posuere consectetur est at lobortis.
</p>
Curabitur blandit tempus porttitor. Sed posuere consectetur est at lobortis.
<blockquote>
This is an example of a blockquote.
</blockquote>
This is an example of a blockquote.
The author stated:
<q>
I'm happy to announce the next book for the upcoming year!
</q>
I'm happy to announce the next book for the upcoming year!
<cite>The Great Gatsby</cite>
<strong></strong>: Indicates strong importance,
typically rendered in bold.
<strong>
This is a bold text
</strong>
NOTE: Don't use <b> elements because they don't add any semantic meaning
<em></em>: Indicates emphasis, usually rendered in italics.
<em>
This is an italic emphasized text
</em>
NOTE: Don't use <i> elements because they don't add any semantic meaning
<mark></mark>: Highlights text to draw attention to it
<span>
Remember to
<mark>
check this section
</mark>
</span>
<small></small>: Represents text of lesser importance, often rendered in smaller font
<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
<time datetime="2025-01-21">
January 21, 2025
</time>
<kdb></kdb>: Represents user input, such as keyboard or voice commands
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
<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.
<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.
water = H2O
y = x2
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
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
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>
<img
src="mountains.jpg"
alt="Scenic view of mountains">
<figcaption>
A scenic view of snowy mountains during sunset
</figcaption>
</figure>
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>
<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>
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
Slides
Slides Repo
Grazie ❤️!