Web Accessibility: Overlooked HTML Patterns
Even developers who know the basics of web accessibility can miss useful native HTML features. This post collects patterns that reduce custom JavaScript, improve semantics, and make interfaces easier to navigate with keyboards and assistive technologies.
1. <dialog> for Accessible Modals
Custom modal implementations often miss focus management, escape-key behavior, or background
inertness. The native <dialog> element provides a better baseline.
<!-- Less accessible modal pattern -->
<div class="modal" id="myModal">
<div class="modal-content">
<span class="close">×</span>
<p>Modal content...</p>
</div>
</div>
<!-- Native accessible modal pattern -->
<dialog id="accessibleModal">
<h2 id="modalTitle">Modal Title</h2>
<div id="modalContent">
<p>Modal content goes here...</p>
</div>
<button id="closeModal">Close</button>
</dialog>
const dialog = document.getElementById('accessibleModal');
const openButton = document.getElementById('openModal');
const closeButton = document.getElementById('closeModal');
openButton.addEventListener('click', () => {
dialog.showModal();
dialog.querySelector('h2').focus();
});
closeButton.addEventListener('click', () => {
dialog.close();
openButton.focus();
});
<dialog> gives you native escape-key handling, focus behavior, and the correct semantics for a
modal surface.
2. <details> and <summary> for Disclosure UI
Expandable content is often built with custom JavaScript, but native disclosure elements already provide keyboard support and state semantics.
<details>
<summary>Section 1</summary>
<p>Content goes here...</p>
<p>Additional content...</p>
</details>
This pattern is keyboard accessible, screen-reader friendly, and does not require JavaScript for the core interaction.
3. <fieldset> and <legend> for Form Groups
Use <fieldset> and <legend> when a group of fields belongs together, especially radio buttons
and checkboxes.
<fieldset>
<legend>Preferred contact method:</legend>
<div>
<input type="radio" id="contact-email" name="contact" value="email" />
<label for="contact-email">Email</label>
</div>
<div>
<input type="radio" id="contact-phone" name="contact" value="phone" />
<label for="contact-phone">Phone</label>
</div>
</fieldset>
Screen readers announce the group label along with each control, which helps users understand the context of the current field.
4. <time> for Dates and Times
Dates should be machine-readable as well as human-readable.
<p>Published: <time datetime="2023-12-01">December 1, 2023</time></p>
<p>Event time: <time datetime="2023-12-01T14:30:00+03:00">2:30 PM</time></p>
This helps assistive technologies, browsers, search engines, and calendar integrations understand the value correctly.
5. <figure> and <figcaption> for Rich Media
alt text should stay concise. When an image needs more explanation, pair it with a caption.
<figure>
<img src="chart-data.png" alt="Bar chart showing quarterly sales in 2023" />
<figcaption>
<strong>Figure 1:</strong> Quarterly sales for 2023, with growth in Q1, Q2, and Q4 and a small
dip in Q3.
</figcaption>
</figure>
The relationship between the media and its explanation becomes programmatic, not just visual.
6. <dl>, <dt>, and <dd> for Definition Lists
Definition lists are useful for glossary entries, FAQ-style metadata, product specs, and other key-value content.
<dl>
<dt>HTML</dt>
<dd>HyperText Markup Language, the standard markup language for documents on the web.</dd>
<dt>CSS</dt>
<dd>Cascading Style Sheets, the language used to describe visual presentation.</dd>
</dl>
7. <abbr> for Acronyms
Use <abbr> when an abbreviation may not be obvious.
<p>
This website uses <abbr title="HyperText Markup Language">HTML</abbr>,
<abbr title="Cascading Style Sheets">CSS</abbr>, and
<abbr title="JavaScript">JS</abbr>.
</p>
8. <output> for Dynamic Results
When a form calculates a result, <output> describes the relationship between inputs and the
computed value.
<form oninput="total.value = (price.valueAsNumber * quantity.valueAsNumber).toFixed(2)">
<label for="price">Price:</label>
<input type="number" id="price" name="price" value="100" />
<label for="quantity">Quantity:</label>
<input type="number" id="quantity" name="quantity" value="1" />
<div>Total: <output name="total" for="price quantity">100.00</output></div>
</form>
9. <meter> and <progress>
Use <progress> for task completion and <meter> for a value within a known range.
<label for="download">Download progress:</label>
<progress id="download" value="70" max="100">70%</progress>
<label for="disk">Disk usage:</label>
<meter id="disk" value="70" min="0" max="100" low="30" high="80" optimum="20">70%</meter>
10. inert for Temporarily Disabled Content
inert removes a subtree from keyboard focus, pointer interaction, and assistive technology access.
It is useful when a modal or blocking panel is open.
<div class="modal-open">
<div class="modal">Modal content...</div>
<div class="page-content" inert>
Page content goes here.
</div>
</div>
11. <datalist> for Native Suggestions
<datalist> gives text inputs native suggestions without a full custom autocomplete component.
<label for="country">Country:</label>
<input type="text" id="country" list="countries" />
<datalist id="countries">
<option value="United States"></option>
<option value="Germany"></option>
<option value="France"></option>
<option value="Italy"></option>
<option value="Spain"></option>
</datalist>
12. <ruby>, <rt>, and <rp> for Pronunciation
Ruby annotations are useful for East Asian text and other pronunciation notes.
<p>
<ruby> 漢 <rt>かん</rt> 字 <rt>じ</rt> <rp>(</rp><rt>kanji</rt><rp>)</rp> </ruby>
are characters used in Japanese.
</p>
Conclusion
These HTML features are easy to overlook, but they improve accessibility, reduce custom JavaScript, and create clearer document semantics. Good accessibility is not only about following a checklist; it is an ongoing practice of choosing the platform feature that gives users the strongest baseline.
For more, see the WAI-ARIA Authoring Practices and the WCAG 2.1 AA guidelines.
