# entry

guid: https://odysee.com/14-year-old-is-one-of-87-donbass:204055b1364c737030cca41ed0de2ea2e7c60749
title: 14 Year Old Is One of 169 Donbass Civilians Maimed By Petal Mines Fired By Ukraine
author: ;Eva K Bartlett
link: https://odysee.com/14-year-old-is-one-of-87-donbass:204055b1364c737030cca41ed0de2ea2e7c60749
hash: ��d� �{�)Ir�G��g
content:
<p><img src="https://thumbnails.lbry.com/K-QSv-zwoSU" width="480" alt="thumbnail" title="14 Year Old Is One of 169 Donbass Civilians Maimed By Petal Mines Fired By Ukraine"></p>*Warning: video contains disturbing/graphic scenes (...which Donbass civilians get no warning for before they are maimed or murdered by Ukrainian shelling).<br>*Title updated (November 28, 2024) with up to date number of victims.<br><br>Fourteen year old Nikita is one of nearly 100 Donbass civilians injured by Ukrainian-fired Petal mines. Nikita, who formerly did breakdancing &amp; Mixed Martial Arts lost his foot after stepping on a mine.<br><br>As of November 28, 2024, 169 civilians have been maimed by these mines, incl. 10 children and numerous elderly. Three of the injured died in the hospital.<br><br><br>MY RELATED:<br><br>-Ukraine turns Donetsk into a minefield using banned ‘Petal’ mines<br>https://odysee.com/@EvaKareneBartlett:9/ukraine-turns-donetsk-into-a-minefield:7?r=EymDGnAtYEjvNCAh13tU3WL6QWGjETBs&amp;lid=375573ed222074153220958b40356704ae21887e<br><br>-Donetsk Emergency Services &amp; Sappers Clear Residential Areas of Ukraine's Mines<br>https://odysee.com/@EvaKareneBartlett:9/donetsk-emergency-services-sappers-clear:2?r=EymDGnAtYEjvNCAh13tU3WL6QWGjETBs&amp;lid=375573ed222074153220958b40356704ae21887e<br><br>-Ukrainian Terrorism: Firing Munitions Containing Petal Mines On Donbass Orphanage, Another War Crime<br>https://odysee.com/@EvaKareneBartlett:9/ukrainian-terrorism-firing-munitions:3?r=EymDGnAtYEjvNCAh13tU3WL6QWGjETBs&amp;lid=375573ed222074153220958b40356704ae21887e<br><br>-The West is silent as Ukraine targets civilians in Donetsk using banned ‘Petal’ mines, Aug 7, 2022<br>https://ingaza.wordpress.com/2022/08/10/the-west-is-silent-as-ukraine-targets-civilians-in-donetsk-using-banned-petal-mines/<br><br>-In Just Under Three Weeks, Ukrainian-Fired Prohibited “Petal” Mines Maim At Least 44 Civilians, Kill 2, in Donetsk Region, August 23, 2022<br>https://ingaza.wordpress.com/2022/08/25/in-just-under-three-weeks-ukrainian-fired-prohibited-petal-mines-maim-at-least-44-civilians-kill-2-in-donetsk-region/<br><br>-What I’ve seen of Ukraine’s war crimes against civilians in the Donbass over the years<br>https://ingaza.wordpress.com/2022/08/10/what-ive-seen-of-ukraines-war-crimes-against-civilians-in-the-donbass-over-the-years/<br><br>-The Donbass: My Articles, Videos &amp; Interviews From/On the Donetsk &amp; Lugansk People’s Republics (2019-present)<br>https://ingaza.wordpress.com/the-donbass-my-articles-videos-interviews-from-on-the-donetsk-lugansk-peoples-republics-2019-present/

attributes:
{"enclosures":[{"url":"https://player.odycdn.com/api/v3/streams/free/14-year-old-is-one-of-87-donbass/204055b1364c737030cca41ed0de2ea2e7c60749/895c87.mp4","type":"video/mp4","length":36344844}]}


guid: https://htmhell.dev/adventcalendar/2022/2/
title: You Don't Need ARIA For That
author: ;Manuel Matuzovic
link: https://htmhell.dev/adventcalendar/2022/2/
hash: [��);l� �ۢG9gU
attributes: {"enclosures":[]}
content:
<p>In web development, writing semantic HTML is important for accessibility, and also provides some nice <a href="https://twitter.com/dennisl/status/1109875307601948672">side effects</a> such as supporting browser "reader" modes, SEO, graceful degradation, and exporting.</p>
<p>Implementing semantic HTML will also greatly reduce the need for <a href="https://www.w3.org/TR/wai-aria-1.1/">ARIA</a> (Accessible Rich Internet Applications). ARIA is a large set of HTML attributes to help accessibility for users of assistive technology, namely screen readers, by better supporting semantics not provided or not supported well via HTML.</p>
<p>ARIA usage certainly has its place. But overall, reduced usage of ARIA will, ironically, greatly increase accessibility. This is due to several reasons including:</p>
<ol>
<li>ARIA is very often implemented incorrectly. This is well known in the industry, but for data, reference the <a href="https://webaim.org/projects/million/#aria">WebAIM Million report</a> which states “Home pages with ARIA present averaged 70% more detected errors than those without ARIA”.</li>
<li>ARIA may not be supported well (even when implemented correctly) by the browser and/or screen reader, which unfortunately is often the case. Reference <a href="https://a11ysupport.io/">a11ySupport.io</a> and <a href="https://www.powermapper.com/tests/screen-readers/aria/">PowerMapper</a> for related information.</li>
<li>ARIA isn't magic (as some web professionals seem to think!). Designs must still be accessible, inclusive, and usable.</li>
<li>ARIA only provides semantics. It doesn't provide any functionality. It doesn't provide any keyboard interaction that's often expected from certain ARIA patterns (the tab panel for example). It doesn't solve accessibility issues outside semantics for assistive technology (such as alternative text, color contrast, reading order, clear label text, captions, etc.)</li>
</ol>
<p>The folllowing cases will illustrate how to use HTML properly so that ARIA is not required. In doing so, the techniques demonstrated will help developers follow the <a href="https://www.w3.org/TR/using-aria/#rule1">first rule of ARIA</a> (to use HTML first if possible), as well as providing more robust code, and most likely, a more accessible experience for the user.</p>
<h2 data-sanitized-id="use-cases">Use cases</h2>
<p>The cases below are just a sampling of issues and include form labels, buttons, links, and images. I find them to be prevalent issues, and in fact I came across all of them “in the wild” (in live websites) over the last couple weeks. There is a bad version followed by a good one and then a note. For demonstration purposes, the code snippets are greatly simplified from the webpages in which they were found.</p>
<p>Remember that correcting the ARIA redundancies may seem trivial on the surface, but can go a long way in:</p>
<ul>
<li>reducing code complexity — less code!</li>
<li>reducing maintenance issues — for example, use of one text node rather than duplicated (also, less code!)</li>
<li>reducing accessibility errors due to value calculations by the browser — for example, the developer may not understand the <a href="https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/#name_calculation">accessible name calculation</a> which can get a bit tricky.</li>
</ul>
<p>Now let's get to the use cases!</p>
<h3 data-sanitized-id="form-labels">Form labels</h3>
<h4>Example 1</h4>
<p data-sanitized-class="code-label">Bad: redundant <code>aria-label</code></p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>...<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">aria-label</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Pickup<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Pickup<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>checkbox<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>... checked=<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token attr-name">"</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>svg...</span><span data-sanitized-class="token punctuation">&gt;</span></span>...<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>svg</span><span data-sanitized-class="token punctuation">&gt;</span></span> </span><br><span data-sanitized-class="highlight-line">    Pickup</span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="code-label">Good: use the inline text within the <code>label</code> (implicit association)</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>...<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Pickup<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>checkbox<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>... checked=<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token attr-name">"</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>svg...</span><span data-sanitized-class="token punctuation">&gt;</span></span>...<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>svg</span><span data-sanitized-class="token punctuation">&gt;</span></span> </span><br><span data-sanitized-class="highlight-line">    Pickup</span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="highlight"><strong>Note:</strong> Remove <code>aria-label</code> for the win! The <code>label</code> wrapped around the <code>input</code> sufficiently provides an accessible name for the input. </p>
<p><strong>Warning:</strong> this example implements implicit input labeling which may have issues with some assistive technology such as Dragon NaturallySpeaking. It's recommended to use explicit association as in Example 2.</p>
<h4>Example 2</h4>
<p data-sanitized-class="code-label">Bad: unwarranted use of <code>aria-labelledby</code></p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>...<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>sortBy<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Sort By:<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>select</span> <span data-sanitized-class="token attr-name">aria-labelledby</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>sortBy<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>...<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Relevance<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Most Recent<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Value<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>select</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="code-label">Good: use the <code>for</code> and <code>id</code> attributes for explicit association</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>...<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>sortBy<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Sort By:<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>select</span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>sortBy<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>...<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Relevance<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Most Recent<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Value<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>select</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="highlight"><strong>Note:</strong> Use fundamental HTML (and not ARIA) for the win! The <code>for</code> and <code>id</code> attributes provide an accessible name for the input.</p>
<h3 data-sanitized-id="image-in-button">Image in Button</h3>
<p data-sanitized-class="code-label">Bad: redundant <code>aria-label</code> and unnecessary role</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>button</span> <span data-sanitized-class="token attr-name">aria-label</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Save $1 on Halloween candy and decor<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>...<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>img</span> <span data-sanitized-class="token attr-name">role</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>presentation<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">src</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>1507288.jpg<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">alt</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Save $1 on Halloween candy and decor<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>button</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="code-label">Good</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>button</span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>...<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>img</span> <span data-sanitized-class="token attr-name">src</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>1507288.jpg<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">alt</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Save $1 on Halloween candy and decor<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>button</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="highlight"><strong>Note:</strong> Remove two ARIA attributes (and duplicate text) for the win! The <code>alt</code> attribute provides the accessible name for the button.</p>
<h3 data-sanitized-id="linked-text">Linked text</h3>
<p data-sanitized-class="code-label">Bad: overwriting pertinent content</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>a</span> <span data-sanitized-class="token attr-name">aria-label</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>view location<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">href</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>/foobar...<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>...<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>span</span> <span data-sanitized-class="token attr-name">data-qa</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>order-address-one<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>...<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>100 W Main St<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>span</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>span</span> <span data-sanitized-class="token attr-name">data-qa</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>order-address-city<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>...<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Strangeville, OH 48000<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>span</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>a</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="code-label">Good: use the existing inline text</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>a</span> <span data-sanitized-class="token attr-name">href</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>/foobar...<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>...<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>span</span> <span data-sanitized-class="token attr-name">data-qa</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>order-address-one<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>...<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>100 W Main St<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>span</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>span</span> <span data-sanitized-class="token attr-name">data-qa</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>order-address-city<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>...<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Strangeville, OH 48000<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>span</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>a</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="highlight"><strong>Note:</strong> There's no need to be overzealous here; the <code>aria-label</code> overwrites the address text as the link name, therefore the address text is not accessible to screen reader users. Linking the address text is sufficient.</p>
<h3 data-sanitized-id="linked-images">Linked images</h3>
<p data-sanitized-class="code-label">Bad: redundant <code>aria-label</code></p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>a</span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>...<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">aria-label</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Earn Cash Back<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">href</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>/foo<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>img</span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>...<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">alt</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Earn Cash Back<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">src</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>foo.png<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">width</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">height</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>a</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="code-label">Good: use the alt text only</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>a</span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>...<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">href</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>/foo<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>img</span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>...<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">alt</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Earn Cash Back<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">src</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>foo.png<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">width</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">height</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>a</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="highlight"><strong>Note:</strong> Remove <code>aria-label</code> and use fundamental HTML for the win! The <code>alt</code> attribute provides the link content.</p>
<h3 data-sanitized-id="decorative-images">Decorative images</h3>
<p data-sanitized-class="code-label">Bad: <code>role</code> attribute used to denote decorative image</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>img</span> <span data-sanitized-class="token attr-name">role</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>presentation<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">src</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>foo.jpg<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">alt</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>a star, a twirl shape, a balloon<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="code-label">Good: use an empty <code>alt</code> value</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>img</span> <span data-sanitized-class="token attr-name">src</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>foo.jpg<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">alt</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span><span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="highlight"><strong>Note:</strong> Remove the <code>role</code> attribute (and remove the alt value) for the win! The empty <code>alt</code> attribute denotes that this is a decorative image.</p>
<h3 data-sanitized-id="script">Script</h3>
<p data-sanitized-class="code-label">Bad: <code>aria-hidden</code> on script tag</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>script</span> <span data-sanitized-class="token attr-name">aria-hidden</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>true<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="code-label">Good: nothing extra needed for accessibility</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>script</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="highlight"><strong>Note:</strong> Remove <code>aria-hidden</code> for the win! Script content (inline JavaScript) isn't output by assistive tech.</p>
<h2 data-sanitized-id="summary">Summary</h2>
<p>Removing ARIA redundancy can reduce code complexity, maintenance issues, and the chance of accessibility errors. Reducing reliance on ARIA makes code more simple and will most likely increase accessibility.</p>
<p>Writing semantic HTML is important for accessibility and also has other benefits. Semantic HTML will greatly reduce the need for ARIA, which is often implemented incorrectly and may not be fully supported. Be sure to use HTML first before using ARIA, such as when coding form labels, buttons and links, and decorative images.</p>
<h2 data-sanitized-id="further-reading">Further reading</h2>
<ul>
<li><a href="https://web.dev/learn/accessibility/aria-html/">ARIA and HTML</a> on web.dev</li>
<li><a href="https://briefs.video/videos/what-is-aria-even-for/">What Is ARIA Even For Webbed Briefs</a> by Heydon Pickering</li>
<li><a href="https://www.a11yproject.com/posts/aria-has-perfect-support/">Myth: ARIA has perfect support</a></li>
<li><a href="https://talks.yatil.net/1jBftF/">ARIA Serious‽ presentation</a> October 2019 by Eric Eggert</li>
<li><a href="https://webaim.org/articles/gonewild/">Web Accessibility Gone Wild</a> by WebAIM</li>
</ul>


guid: https://htmhell.dev/adventcalendar/2022/3/
title: Using SRI to protect from malicious JavaScript
author: ;Manuel Matuzovic
link: https://htmhell.dev/adventcalendar/2022/3/
hash: De��_���î����gb
attributes: {"enclosures":[]}
content:
<p>At some point of developing a website, there might come a time where we need to <a href="https://saptaks.blog/posts/progressive-enhancement-is-not-anti-js.html">progressively enhance using JavaScript</a>. There are few different options of how you add JavaScript. Firstly, we can write our own script using vanilla JS only, and self host the JavaScript file. However, often we find ourselves needing to use a JavaScript framework or library to make our life a little easier. We can definitely download all the JavaScript framework and libraries we are using and self host them in our server, but most framework websites recommend using a CDN.</p>
<h2 data-sanitized-id="cdns-for-javascript-frameworks-and-libraries">CDNs for JavaScript frameworks and libraries</h2>
<p><a href="https://www.cloudflare.com/en-gb/learning/cdn/what-is-a-cdn/">CDN</a> or Content Delivery Networks are a group of servers which stores duplicate copies of data and serves them to the user from the server closest to them to improve performance. CDNs are often used to serve static files like CSS and JS files by frameworks and libraries. Developers used CDNs for serving JS files not only because CDNs are usually faster, but also since a lot of commonly used frameworks served via CDN used to already be cached in your browser. For example, let’s say there are 3 websites - websiteA.﻿com, websiteB.﻿com. Both of these websites use jQuery. To use CDN, both of these websites can use the following code in their HTML file:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>script</span> <span data-sanitized-class="token attr-name">src</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>https://code.jquery.com/jquery-3.6.1.js<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token script"></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>script</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>Now, when a user visits, websiteA.﻿com for the first time, the browsers requests for the jQuery file from <code>https://code.jquery.com</code> CDN and used to cache it. So, when the user would visit websiteB.﻿com, the jQuery file were already cached in the browser, thus improving performance a lot. However, most browsers have <a href="https://www.stefanjudis.com/notes/say-goodbye-to-resource-caching-across-sites-and-domains/">stoppped resource caching</a> to prevent tracking users across websites.</p>
<figure>
  <img src="https://htmhell.dev/images/advent2022/15/cdn-usage-ranking-desktop.png" alt="Bar chart which provides a view of CDN usage for mobile sites broken up for top 1,000, 10,000, 100,000, 1 million and 10 million popular sites as per Google CRUX data. For Top 1,000 sites the CDN adoption is 64%. For the top 10,000 sites, it's 63%. For the top 100,000 sites, it's 52%. For the top 1 million sites, it's 37%. For the top 10 million sites, it's 29%.">
  <figcaption><a href="https://almanac.httparchive.org/en/2022/cdn#fig-3">CDN usage by site popularity</a> on mobile as reported in Web Almanac 2022</figcaption>
</figure>
<p>Even though this change removes the performance improvements from resource caching, CDNs are still usually faster and simpler for serving CSS and JS files and does continue to be used widely. According to Web Almanac 2022, 64% of top 1,000 websites use <a href="https://almanac.httparchive.org/en/2022/cdn">CDN</a> to serve various content.</p>
<h2 data-sanitized-id="security-issue">Security issue</h2>
<p>Using CDN to serve JavaScript comes with certain risks. One of the reasons privacy and security focused users are bit squirmish about JS is because a malicious JS can really harm your user. It can range from being misused for tracking and surveillance to compromising users private data. So, if all websites use the same CDN to serve a JS file, an attacker now needs to gain control of only the CDN server instead of all individual servers. Once they gain control, they can inject malicious code into the JS file, and it gets served to all end users of websites that use the CDN.</p>
<h2 data-sanitized-id="how-does-sri-help?">How does SRI help?</h2>
<p>At this point, the solution to this seems to be to self host all your JavaScript codes instead of using a CDN. But that would be a step backward in terms of performance and not the favourable solution in many situations. This is where <a href="https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity">Subresource Integrity (or SRI)</a> helps.</p>
<p>Subresource integrity is a way of telling the browser how to verify that the JS it has fetched from the CDN is an untampered JS file. SRI uses the very popular concept of file hashing to verify that the file is still the same. Let’s look into what a <code>&lt;srcipt&gt;</code> code with Subresource integrity to fetch jQuery would look like.</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>script</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token attr-name">src</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>https://code.jquery.com/jquery-3.6.1.js<span data-sanitized-class="token punctuation">"</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token attr-name">integrity</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>sha256-3zlB5s2uwoUzrXK3BT7AX3FyvojsraNFxCc2vC/7pNI=<span data-sanitized-class="token punctuation">"</span></span></span><br>  <span data-sanitized-class="token attr-name">crossorigin</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>anonymous<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token script"></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>script</span><span data-sanitized-class="token punctuation">&gt;</span></span></code></pre>
<p>The above code is what you get if you go to <a href="https://releases.jquery.com/">https://releases.jquery.com/</a> and click on the release you want to use. Now let’s break it down to see what it means.</p>
<h3 data-sanitized-id="integrity">integrity</h3>
<p>The <code>integrity</code> attribute contains the file hash. The <code>integrity</code> attribute has 2 parts - the hashing algorithm and the hash of the file. In the above code, <code>sha256</code> is the hashing algorithm which tells the browser which algorithm to use while computing hash of the received file. The part after <code>sha256</code>- is the base64 encoding of the expected hash of the untampered file provided by the code author. So when the browser comes across the above code, it fetches the jQuery file from the CDN server, generates the hash for the file it received and compares it with the hash mentioned in the <code>integrity</code> attribute. If the hashes don’t match, then the browser will refuse to execute the script and throw a network error saying fetching of the resources failed.</p>
<h3 data-sanitized-id="crossorigin">crossorigin</h3>
<p>Since the CDN resource is not present in the same origin, the <code>crossorigin</code> attribute must be present to make the <a href="https://www.w3.org/TR/SRI/#is-response-eligible-for-integrity-validation">response eligible for integrity validation</a>. Without the <code>crossorigin</code> attribute, the browser will load the script as if the <code>integrity</code> attribute was not present. We set the value of <code>crossorigin</code> attribute to <code>"anonymous"</code> to ensure that no user credentials or cookie informations are sent to the CDN server.</p>
<h2 data-sanitized-id="how-to-generate-sri?">How to generate SRI?</h2>
<p>In most cases, the framework or library we are importing using <code>&lt;script&gt;</code> tag should have the SRI code already mentioned in their documentation. For example, as we saw before, if we go to jQuery’s release page, and click on the release we want, the example code already has the <code>integrity</code> and <code>crossorigin</code> attribute values mentioned. Bootstrap also has the <code>integrity</code> and <code>crossorigin</code> attributes mentioned in their quickstart page. But there are many other frameworks that don’t in which case we will need to generate the hash by ourselves. Also, it’s recommended to use SRI for the scripts written by the developer for the website specifically. There can always be a scenario where the attacker gets access to only certain files, so SRI will ensure that the resources served by the server are untampered.</p>
<figure>
  <img src="https://htmhell.dev/images/advent2022/15/sri-hash-function-usage.png" alt="Bar chart showing percent of HTML elements with SRI using various hash functions. SHA-384 is used in 58.4% of elements with SRI in desktop
websites and 60.7% of elements with SRI in mobile websites. SHA-256 is used in 32.4% of elements with SRI in desktop websites and
30.8% of elements with SRI in mobile websites. SHA-512 is used in 10.9% of elements with SRI in desktop websites and 9.9% of
elements with SRI in mobile websites.">
  <figcaption>
  <a href="https://almanac.httparchive.org/en/2022/security#subresource-integrity" rel="noopener noreferrer">Percentage usage of SRI</a> hash function as mentioned in Web Almanac 2022
  </figcaption>
</figure>
<p>To create a hash function, there are 3 different hash functions that are supported for SRI - sha256, sha384 and sha512. We need to use one of these 3 functions to compute the hash for the <code>.js</code> files and <code>.css</code> files and then use those values. The easiest way of doing this is using <a href="https://www.srihash.org/">https://www.srihash.org/</a>. All we need to do is paste the link to the resource we want to generate a hash for, and the website generates the HTML that we need to add. For example, if we wanted to get the HTML for the script tag to import react, all we need to do is paste <a href="https://unpkg.com/react@18/umd/react.production.min.js">https://unpkg.com/react@18/umd/react.production.min.js</a> from React’s CDN page in the input field, chose the hash function we want, and it generates the following output:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>script</span> <span data-sanitized-class="token attr-name">src</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>https://unpkg.com/react@18/umd/react.production.min.js<span data-sanitized-class="token punctuation">"</span></span> <br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token attr-name">integrity</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>sha384-tMH8h3BGESGckSAVGZ82T9n90ztNXxvdwvdM6UoR56cYcf+0iGXBliJ29D+wZ/x8<span data-sanitized-class="token punctuation">"</span></span></span><br>	<span data-sanitized-class="token attr-name">crossorigin</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>anonymous<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token script"></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>script</span><span data-sanitized-class="token punctuation">&gt;</span></span></code></pre>
<p>But if you fancy doing it manually, especially for your local JavaScript files and CSS files, we can do that as well using openssl in a command line.</p>
<pre data-sanitized-class="language-bash"><code data-sanitized-class="language-bash"><span data-sanitized-class="highlight-line">openssl dgst -sha384 -binary FILENAME.js <span data-sanitized-class="token operator">|</span> openssl base64 -A</span></code></pre>
<p>The above code will generate the base64 encoded hash to be put in the integrity attribute. For example, if we wanted to create the hash for the same react file manually, firstly we will need to download the JS file from <a href="https://unpkg.com/react@18/umd/react.production.min.js">https://unpkg.com/react@18/umd/react.production.min.js</a>, then open a terminal and enter <code>openssl dgst -sha384 -binary react.production.min.js | openssl base64 -A</code>. This gives me the output <code>tMH8h3BGESGckSAVGZ82T9n90ztNXxvdwvdM6UoR56cYcf+0iGXBliJ29D+wZ/x8</code> for React 18.2.0. Since I used the hash function <code>sha384</code> and with the above output, the value of my <code>integrity</code> attribute will be <code>sha384-tMH8h3BGESGckSAVGZ82T9n90ztNXxvdwvdM6UoR56cYcf+0iGXBliJ29D+wZ/x8</code>. Hence, we get a HTML same as the one we get from <a href="http://srihash.org/">srihash.org</a></p>
<p>The reason I really love Subresource Integrity is because it’s such an important feature that is baked using HTML attributes. It shows that a lot can be achieved, even in making a website secure just by learning HTML better. Just add an <code>integrity</code> attribute and <code>crossorigin</code> attribute to ensure that untampered JS framework codes are fetched. Also, SRI is supported by <code>&lt;link&gt;</code> tags as well so that one can ensure that the CSS files are also fetched untampered. In <a href="https://darknetdiaries.com/transcript/52/">episode 52 of Darknet Diaries</a>, Jack Rhysider and Jonathan Klijnsma discuss about how a tampered modernizr JavaScript file might have caused the data breach in British Airways, that could have been avoided using SRI</p>


guid: https://htmhell.dev/adventcalendar/2022/4/
title: Landmarks and where to put them
author: ;Manuel Matuzovic
link: https://htmhell.dev/adventcalendar/2022/4/
hash: 8��� f� tf1�
attributes: {"enclosures":[]}
content:
<p>Heading elements (<code>h1</code> through to <code>h6</code>) are used to give structure to the content of your page. They're important for SEO, make your pages more readable and, of course, also help people that use assistive technologies navigate through your page. Somewhat less known are landmark elements. These are elements that are used to define the structure of your entire HTML and you probably know some of them already: <code>nav</code>, <code>main</code> and <code>footer</code> are all landmark elements (well, most of the time. We'll get to that.)</p>
<p>Many of these elements were only introduced with HTML5 (compared to the headers that have been with us for as long as HTML existed) so if you haven't used them extensively yet, that's not that unusual. Let's figure out what they are and where you can (and can not) use them.</p>
<h2 data-sanitized-id="landmarks-101">Landmarks 101</h2>
<p>When you look up landmark elements, you'll find that they also go by another name: sectioning elements. You can take that quite literally: they section off different parts of your page into unique semantic blocks.</p>
<p>Knowing which part of a website has which role is helpful to many. They can help browsers determine what part of the page to show in a reader mode, they let search engine know what pages on your site are most important (linked from the <code>nav</code>) and they let users natively move focus to the <code>main</code> content without you having to bring your own skip-links: assistive technologies can show a list of all landmarks and your visitors can use that to navigate across your page.</p>
<p><img src="https://htmhell.dev/images/advent2022/5/landmark.png" alt="VoiceOver on macOS showing the lis of landmarks for htmhell.dev."></p>
<p>In other words, landmarks are a bunch of elements that help you define the structure of a page: you use them to show which set-of-links is the navigation (<code>nav</code>), what part of the page is the intro (<code>header</code>) and the main content (<code>main</code>). If you page contains a stand-alone piece of content you could put that in an <code>article</code> and if it contains secondary information you put that in an <code>aside</code>. And if something it its own sectioned-off part you use ...a  <code>section</code>.</p>
<p>Here's an overview of the landmark elements in HTML, their ARIA role and what they mean:</p>
<ul>
<li><code>aside</code> (role: <code>complementary</code>) can be used to show content that is complementary to the main subject of the page. For example, links to related documents or meta info related to the main subject.</li>
<li><code>footer</code> (role: <code>contentinfo</code>) is where you put all the information about a page. Typically that's things like copyright info, related links, the author</li>
<li><code>form</code> (role: <code>form</code>) <em>can</em> be a landmark element if it has a accessible name (set with <code>aria-label</code>, <code>aria-labelledby</code> or <code>title</code> attributes)</li>
<li><code>header</code> (role: <code>banner</code>) is where your page's "introduction" goes. Things like your logo, search and main navigation all go in here.</li>
<li><code>main</code> (role: <code>main</code>) contains the main content or functionality of your page.</li>
<li><code>nav</code> (role: <code>navigation</code>) is where you provide navigational links. They can be for your entire website (think your main menu), but also for your current page (think table of contents).</li>
<li><code>section</code> (role: <code>region</code>) This is a "generic standalone section of a page". Essentially, if you have a part of the page that stands alone, try to go down this list and if none of them fit but it's still a separate part of the page, use a section. Like <code>form</code>s, it'll only be a landmark if it also has an accessible name.</li>
</ul>
<p>There is still one more landmark that we need to discuss: the <code>search</code> landmark. All the landmarks above are HTML elements with a specific landmark role, but the <code>search</code> landmark role has no associated HTML element. It only exists in ARIA. As you might guess, the search landmark is used to indicate search functionality and practically, you'd add a <code>search</code> role to a <code>form</code> element to change it from a generic form to a search form.</p>
<h2 data-sanitized-id="where-(not)-to-put-them-the-ideal-web-page-structure">Where (not) to put them: the ideal web page structure</h2>
<p>Now that you know which landmarks there are, how do you use them in a web page? "The ideal web page structure"  is quite a heavy promise, but we're limiting it to the ideal <em>landmark</em> structure. Here's what that looks like:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>header</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token comment">&lt;!-- logo etc --&gt;</span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>nav</span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>nav</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>form</span> <span data-sanitized-class="token attr-name">role</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>search<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>form</span><span data-sanitized-class="token punctuation">&gt;</span></span> <span data-sanitized-class="token comment">&lt;!-- if it exists --&gt;</span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>header</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>main</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token comment">&lt;!-- what your page is all about --&gt;</span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>main</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>aside</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token comment">&lt;!-- complementary information --&gt;</span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>aside</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>footer</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token comment">&lt;!-- copyright notice etc --&gt;</span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>nav</span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>nav</span><span data-sanitized-class="token punctuation">&gt;</span></span> <span data-sanitized-class="token comment">&lt;!-- if you want to --&gt;</span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>footer</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>Your page begins with the <code>header</code> and ends with the <code>footer</code>. Your navigation and search landmarks will usually go into the <code>header</code> element and can sometimes fit well in the <code>footer</code> element as well.</p>
<p>Directly after the header is the <code>main</code> content. This is the most important part of your page so you put it as high as possible. Directly after the <code>main</code> element you can put any complementary information that relates to your entire page.</p>
<p>What this does it create a "landmark outline" of your page that looks like this:</p>
<ul>
<li>Banner</li>
<li>Navigation</li>
<li>Search</li>
<li>Main</li>
<li>Complementary</li>
<li>Contentinfo</li>
<li>Navigation</li>
</ul>
<p>Notice that unlike a heading structure, your landmarks don't add any hierarchy to a page. Each section of your page is meant to be its own part. It also doesn't matter how many other elements you add around or inside them. You are free to wrap everything in as many divs as <s>your javascript framework requires</s> you need to style your page.</p>
<p>When you add landmark elements, you're changing the semantics of your web page so there are some key things to keep in mind:</p>
<h3 data-sanitized-id="not-all-nesting-is-created-equally">Not all nesting is created equally</h3>
<p>Even though your landmarks don't add hierarchy, where you put your landmark elements will determine if they even are landmarks. Both <code>header</code> and <code>footer</code> elements are only landmarks if they are inside your <code>body</code> element, but not if they're inside other sectioning elements.</p>
<p>A <code>header</code>/<code>footer</code> in any of the following elements indicate they're the header or footer for just that sectioning element, and they are taken out of the landmark structure:</p>
<ul>
<li><code>article</code></li>
<li><code>aside</code></li>
<li><code>main</code></li>
<li><code>nav</code></li>
<li><code>section</code></li>
</ul>
<p>Depending on who you ask (the <a href="https://www.w3.org/WAI/ARIA/apg/example-index/landmarks/complementary.html">ARIA authoring practice guide</a>, in this case), adding an <code>aside</code> into any of the above is also a bad idea. If something is complementary then by definition it's not part of the <code>main</code> or <code>article</code>. This doesn't track with the official <a href="https://html.spec.whatwg.org/multipage/sections.html#the-aside-element">HTML5 specification</a>, that has examples of using <code>aside</code> for things like pull quotes in articles.</p>
<p>Neither is correct or wrong, but keep in mind though that the more landmarks you add, the longer it takes assistive tech to go through the list of landmarks and the more annoying it will be for your visitors.</p>
<h3 data-sanitized-id="sometimes-just-adding-landmark-elements-isnt-enough">Sometimes just adding landmark elements isn't enough</h3>
<p>As mentioned in the overview of landmarks, just adding a <code>form</code> or <code>section</code> won't make them landmarks. You need to give them an accessible name or explicit role, and there's a few ways to do that:</p>
<ol>
<li>Adding a <code>aria-labelledby</code> attribute that contains the <code>id</code> of another element with the title of the form or section.</li>
<li>Adding a <code>aria-label</code> or <code>title</code> attribute to the element. The title attribute will also be visible on hover so keep that in mind.</li>
<li>Adding an explicit <code>role</code> attribute with <code>form</code> or <code>region</code> as the value.</li>
</ol>
<h3 data-sanitized-id="you-cant-just-keep-adding-them">You can't just keep adding them</h3>
<p>The <code>banner</code> ,  <code>contentinfo</code> and  <code>main</code> landmark roles should only be added to your page once. There is nothing in HTML5 that prevents your site from having multiple of them but from a semantic standpoint it doesn't make sense and for people using assistive technologies it's confusing. Your page should have one header, one footer and one main area. If you need more, maybe you just need another page.</p>
<h3 data-sanitized-id="naming-landmark-elements">Naming landmark elements</h3>
<p>If you have multiple of the same elements, for example you use a <code>nav</code> element for your top-level website navigation, and also for the table of contents on a page, you should give each of them a unique accessible name. If you don't, then visitors using assistive technologies will not know which is which. You can add a name using <code>aria-labelledby</code>, <code>aria-label</code> or <code>title</code> attributes.</p>
<p>When adding a name to a landmark element, it can be very tempting to add the role as well because that's how you would describe it in natural speech. For example, for your top level navigation you might want to add an <code>aria-label</code> of "Main navigation".</p>
<p>If you do that however, what assistive technology will announce is "Main navigation <em>navigation</em>" and your visitor gets to hear that it's navigation twice. Assistive technogies already append the role, so you shouldn't. In this case, naming your navigation "Main" is enough.</p>
<h3 data-sanitized-id="dont-just-replace-your-divs-with-sections">Don't just replace your <code>div</code>s with <code>section</code>s</h3>
<p>A div is not a button, and a section is not a div. When HTML5 just came out, a lot of advice boiled down to "Use section elements because they're more semantic than divs" but of course, that only works if the divs you replace had semantic value. For the most parts, your <code>div</code>s wont have any specific semantics: they don't tell the browser what each part of the structure is for.</p>
<p>And that's fine! You can use your divs for styling, to structure your DOM in such a way that you can use CSS and JavaScript to build what you want to build. And when you have a portion of the page that is it's own standalone or self-contained part, you can add a section (and make sure to name it).</p>
<h2 data-sanitized-id="on-roles-and-elements">On Roles and Elements</h2>
<p>Throughout this article I've used Elements (e.g. <code>header</code>) and Roles (e.g. <code>banner</code>). So what's with those? Are they the same thing? Why do they have different names?</p>
<p>HTML5 is the official specification in terms of what elements have what semantic value. However, the HTML5 specification doesn't cover all possible semantics. To provide richer semantics, ARIA was created as a technology that sits on top of HTML that can help "plug the gaps".</p>
<p>It's generally better to use HTML where possible: the <a href="https://www.w3.org/TR/using-aria/#rule1">first rule of aria</a> is <em>don't use aria</em>:</p>
<blockquote>If you can use a native HTML element or attribute with the semantics  and behavior you require already built in, instead of re-purposing an  element and adding an ARIA role, state or property to make it  accessible, then do so.</blockquote>
<p>Practically this means that instead of adding a <code>role="banner"</code> to your div to make it a header element, you should just use the <code>header</code> element.</p>
<p>So why does <code>role="banner"</code> exist? It exists for some very pragmatic reasons: While yes, using a header element is better, not all websites are started anew, and not all websites are built with modern systems. Some systems might have no way of adding a <code>header</code> element. In those systems, using a <code>role</code> attribute means that you can still provide the correct semantics.</p>
<p>If you write HTML you should always prefer to use the HTML elements and if you do, you don't have to add the <code>role</code> attribute (there are <a href="https://www.scottohara.me/blog/2019/01/12/lists-and-safari.html">some places where you should</a>, but they're not landmark-related).</p>
<p>As for the names being different: for better or for worse ARIA and HTML are written by different people in different places, with different needs. While for ARIA it makes sense to call the navigation "navigation", HTML authors would go crazy if for every menu they had to write <code>&lt;navigation&gt;</code> instead of just <code>&lt;nav&gt;</code>. The names in ARIA in comparison are written to also make sense outside of the concept of a HTML page. A page has a footer, but any bit of content might have "content info" that gives additional information.</p>
<h2 data-sanitized-id="wrapping-up">Wrapping up</h2>
<p>Your page should almost certainly have a top level <code>header</code>, <code>main</code> and <code>footer</code>, but you don't want to add a bunch of them. If it's part of a larger website then you'll want to use a <code>nav</code> element to link to other pages. If you use multiple <code>nav</code> elements you'll want to name them so your visitor can tell them apart. You should try and use the HTML elements but if you absolutely can not, ARIA gives you the <code>role</code> attribute. Landmarks have a name and a role, and both get read out by assistive technologies.</p>
<p>Used resources:</p>
<p><a href="https://www.w3.org/WAI/ARIA/apg/example-index/landmarks/HTML5.html">https://www.w3.org/WAI/ARIA/apg/example-index/landmarks/HTML5.html</a></p>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element#content_sectioning">https://developer.mozilla.org/en-US/docs/Web/HTML/Element#content_sectioning</a></p>
<p><a href="https://www.w3.org/TR/wai-aria-1.2/#landmark">https://www.w3.org/TR/wai-aria-1.2/#landmark</a></p>
<p><a href="https://html.spec.whatwg.org/">https://html.spec.whatwg.org</a></p>


guid: https://htmhell.dev/adventcalendar/2022/5/
title: Reading the meter
author: ;Manuel Matuzovic
link: https://htmhell.dev/adventcalendar/2022/5/
hash: l��~M�u����R�Y
attributes: {"enclosures":[]}
content:
<p>The <code>&lt;meter&gt;</code> element is a little known and rarely used semantic element. It's a non-interactive <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_categories#form-associated_content">form element</a> that renders as a partially filled horizontal bar. Browsers provide user-agent styles, but the <code>&lt;meter&gt;</code> element can also be styled.</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>10<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>200<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>130<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>The example above in Safari, Chrome and Firefox on MacOS.</p>
<p><img src="https://htmhell.dev/images/advent2022/7/meter-browsers.png" alt="The meter element rendered with slightly different shapes, sizes and colors in Safari, Chrome and Firefox."></p>
<p><code>&lt;meter&gt;</code> is sometimes confused with the <code>&lt;progress&gt;</code> element as they are visually similar, but <code>&lt;meter&gt;</code> represents a current value in a known range, while <code>&lt;progress&gt;</code> represents something that is <em>in</em> progress, like a file upload.</p>
<p>The definition found <a href="https://html.spec.whatwg.org/multipage/form-elements.html#the-meter-element">in the HTML spec</a> includes some examples of potential uses.</p>
<blockquote>The meter element represents a scalar measurement within a known range, or a fractional value; for example disk usage, the relevance of a query result, or the fraction of a voting population to have selected a particular candidate.</blockquote>
<p>The spec also states that it should not represent an arbitrary range, meaning there should be a known maximum value.</p>
<h2 data-sanitized-id="attributes">Attributes</h2>
<p>Six attributes determine how the <code>&lt;meter&gt;</code> element renders and its basic semantics. The only required attribute is <code>value</code>, and all attributes must be a valid <a href="https://www.freecodecamp.org/news/floating-point-definition/">floating point number</a> (e.g., 5, -22, 7.25).</p>
<p>The following attributes set the value and range.</p>
<ul>
<li><code>value</code> - Current value. Must be between <code>min</code> and <code>max</code>. It can be the only attribute if it's expressed as a decimal fraction (e.g., 0.65, which would represent 65%).</li>
<li><code>min</code> - Minimum value for the range. Must be less than <code>max</code>. Defaults to 0 if not specified.</li>
<li><code>max</code> - Maximum value for the range. Must be greater than than <code>min</code>. Defaults to 1 if not specified.</li>
</ul>
<p>The following attributes set boundary segmentation. The bar can render in different colors based on their value. They also can provide additional semantic information for screen readers to announce.</p>
<ul>
<li><code>low</code> - Upper boundary of the low end of the range, or where the low range ends. Must be greater than <code>min</code> and less than <code>high</code> or <code>max</code>.</li>
<li><code>high</code> - Lower boundary of the high end of the range, or where the high range begins. Must be less than <code>max</code> and greater than <code>low</code>.</li>
<li><code>optimum</code> - Indicates the optimum point in the range. If unspecified, the midpoint between minimum and maximum values is the optimum.</li>
</ul>
<p>A summation from the HTML spec ...</p>
<ul>
<li>minimum value ≤ actual value ≤ maximum value.</li>
<li>minimum value ≤ low boundary ≤ high boundary ≤ maximum value.</li>
<li>minimum value ≤ optimum point ≤ maximum value.</li>
</ul>
<p>All of the following are valid:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>.65<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>10<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>20<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>35<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>1<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">high</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>80<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">optimum</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>85<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>20<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<h2 data-sanitized-id="semantics-and-labeling">Semantics and labeling</h2>
<blockquote>Authors are encouraged to include a textual representation of the gauge's state in the element's contents, for users of user agents that do not support the <code>&lt;meter&gt;</code> element. – <a href="https://html.spec.whatwg.org/multipage/form-elements.html#the-meter-element">HTML spec</a></blockquote>
<p>There are several screen readers in use today, and without access to all of them it's hard to know how well <code>&lt;meter&gt;</code> is supported.</p>
<p>According to a <a href="https://webaim.org/projects/screenreadersurvey9/">survey of screen reader users</a> by WebAIM released in 2021, the most commonly used <a href="https://webaim.org/projects/screenreadersurvey9/#used">desktop/laptop screen readers</a> among respondents were JAWS and NVDA, and the most commonly used <a href="https://webaim.org/projects/screenreadersurvey9/#mobilescreenreaders">mobile screen reader</a> was VoiceOver. On desktop/laptop the most common <a href="https://webaim.org/projects/screenreadersurvey9/#browsercombos">browser and screen reader combinations</a> were JAWS and Chrome (32.5%) and NVDA and Chrome (16%).</p>
<p>In 2018 Scott O'Hara <a href="https://scottaohara.github.io/a11y_styled_form_controls/src/meter/">tested and documented</a> the effect of styling on the <code>&lt;meter&gt;</code> element:</p>
<blockquote>JAWS 2018 + Chrome (latest)  — Chrome + JAWS will announce both styled and unstyled <code>meter</code> elements and their current value, with no indication of their low, high, or max values. If a <code>meter</code> is provided an accessible name by `aria-label` or <code>aria-labelledby</code>, it will be completely ignored by JAWS.</blockquote>
<blockquote>NVDA 2018.2.1 + Chrome (latest) — Chrome + NVDA do not have issues with announcing styled meters unless they are given an accessible name via aria-label or aria-labelledby. Doing so will result in NVDA only announcing the accessible name and none of the meter's current state.</blockquote>
<blockquote>NVDA 2018.2.1 + Firefox 63 (nightly) — NVDA will announce nothing but the accessible name to meter elements, regardless of if they are styled or not.</blockquote>
<blockquote>VoiceOver + Safari 11.1.1 &amp; 12.0 on macOS High Sierra — VoiceOver will completely ignore a styled meter element unless it has an accessible name set by aria-label or aria-labelledby. But even then, VoiceOver will only announce the accessible name and none of the meter's current state.</blockquote>
<blockquote>VoiceOver + Safari on iOS 11.4 &amp; 12.1 — VoiceOver will completely ignore the existence of meter elements, regardless of if they are styled or not.</blockquote>
<p>Using NVDA and Narrator via <a href="https://assistivlabs.com/">Assistiv Labs</a> and VoiceOver with Safari on MacOS and iOS we can we can see if support for the <code>&lt;meter&gt;</code> element has improved since 2018. The tests below use the following versions of screen readers and browsers:</p>
<ul>
<li>NVDA (2022.3) + Chrome (106)</li>
<li>NVDA (2022.3) + Firefox (105)</li>
<li>Narrator (21H2) + Edge (106)</li>
<li>VoiceOver + Safari MacOS 15.6.1</li>
<li>VoiceOver + Safari iOS 15.6.1</li>
</ul>
<p>Narrator (Windows) and VoiceOver (Mac) are included in their respective operating systems and <a href="https://www.nvaccess.org/download/">NVDA</a> is a free open source screen reader available for Windows. <a href="https://www.freedomscientific.com/products/software/jaws/">JAWS</a> is paid screen reader for Windows and is not included in these tests.</p>
<p>Using our original example:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>.65<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>10<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>20<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>35<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>1<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">high</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>80<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">optimum</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>85<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>20<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p><a href="https://codepen.io/superterrific/pen/QWrJVPm">View at CodePen</a></p>
<ul>
<li>NVDA + Chrome announces "progress bar" + the value (e.g, "progress bar .65", "progress bar 10").</li>
<li>NVDA + Firefox announces "progress bar" + the value (e.g, "progress bar .65", "progress bar 10").</li>
<li>Narrator + Edge announces the value as a percent + "meter" (e.g., "65% meter").</li>
<li>VoiceOver MacOS announces the value as a percent + "level indicator" if <code>min</code> and/or <code>max</code> are the only attributes present (e.g., "65%, level indicator). If <code>low</code>,  <code>high</code>, or <code>optimum</code> are present the value is announced as "critical value", "suboptimal value" or "optimal value" + "level indicator" (e.g., "optimal value, level indicator").</li>
<li>VoiceOver iOS announces the same as MacOS but does not include "level indicator" (e.g., "65%", "optimal value").</li>
<li>None of them explicitly announce the <code>min</code>, <code>max</code>, <code>low</code>, <code>high</code> or <code>optimum</code> values.</li>
</ul>
<h3 data-sanitized-id="fallback-text">Fallback text</h3>
<p>Using fallback text within the <code>&lt;meter&gt;</code> is the textual representation mentioned in the spec. Adding fallback text to our original example:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>.65<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>65% complete<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>10<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>10 out of 100<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>20<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>30/100<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>35<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>35 out of 100 items<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>1<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">high</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>80<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">optimum</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>85<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>20<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>20 centimeters long out of 100 total<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p><a href="https://codepen.io/superterrific/pen/QWrJVPm">View at CodePen</a></p>
<ul>
<li>NVDA + Chrome ignores fallback text and announces value only (e.g, "progress bar .65", "progress bar 10").</li>
<li>NVDA + Firefox announces progress bar + fallback text (e.g., "progress bar 65% complete").</li>
<li>Narrator + Edge ignores fallback text and announces value only (e.g., "65% meter").</li>
<li>VoiceOver MacOS announces fallback text + level indicator if <code>min</code> and/or <code>max</code> are the only attributes present (e.g., "65% complete, level indicator"). If <code>low</code>, <code>high</code>, and/or <code>optimum</code> are present the fallback text is announced + "critical value", "suboptimal value" or "optimal value" + "level indicator (e.g., "20 centimeters long out of 100 total, critical value, level indicator").</li>
<li>VoiceOver iOS announces the same as MacOS but does not include "level indicator" (e.g., "65% complete").</li>
</ul>
<p>In addition to NVDA + Chrome and Narrator + Edge, fallback text is also not announced in NVDA + Edge and MacOS + Chrome. Support for the feature likely comes from the browser engine rather than the screen reader given that both Chrome and Edge use Blink.</p>
<h3 data-sanitized-id="labeling">Labeling</h3>
<p>Labeling can provide additional information or meet the requirements of your use case (e.g., you need a visible label). Using our original example and adding various labeling techniques:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>meter-1<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Tasks<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>meter-1<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>.65<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>10<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">aria-label</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>cookies eaten<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>10 out of 100<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>20<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">title</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>articles written<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>30/100<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>p</span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>meter-2<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Shows watched<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>35<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">aria-labelledby</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>meter-2<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>p</span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>meter-3<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Length in centimeters<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>1<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">high</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>80<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">optimum</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>85<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>20<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">aria-describedby</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>meter-3<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p><a href="https://codepen.io/superterrific/pen/QWrJVPm">View at CodePen</a></p>
<ul>
<li>NVDA + Chrome announces all labeling techniques (e.g., "Tasks, progress bar 0.65").</li>
<li>NVDA + Firefox announces all labeling techniques (e.g., cookies eaten, progress bar 10 out of 100).</li>
<li>Narrator + Edge announces all labeling techniques (e.g., "articles written, 13% meter")</li>
<li>VoiceOver MacOS announces all labeling techniques except <code>title</code> (e.g., "30/100, level indicator" without announcing "articles written").</li>
<li>VoiceOver iOS announces all labeling techniques including <code>title</code>.</li>
<li>Using <code>label</code> or <code>aria-label</code> added a double announcement of the label (e.g., "Tasks, 65% complete, tasks, level indicator" or "Tasks, Tasks 65% meter") for VoiceOver and Narrator.</li>
</ul>
<p>There have been a few of improvements in screen reader support for the <code>&lt;meter&gt;</code> element since 2018.</p>
<ul>
<li>NVDA as of version 2020.4 using an accessible name (<code>aria-label</code> or <code>aria-labeledby</code>) no longer voids announcement of the <code>&lt;meter&gt;</code>'s state.</li>
<li>VoiceOver on iOS no longer ignores an unstyled <code>&lt;meter&gt;</code> element.</li>
</ul>
<p>It's unknown if accessible names still cause JAWS to ignore the content of the <code>&lt;meter&gt;</code> element.</p>
<h2 data-sanitized-id="color-contrast">Color Contrast</h2>
<p>Browsers provide user-agent styles for the <code>&lt;meter&gt;</code> element, and each browser uses slightly different colors. Generally the default colors don't provide sufficient contrast against a white background to pass Web Content Accessibility Guidelines (WCAG) AA 2.1 standard of at least a 3.1 contrast ratio between graphical elements and adjacent colors (<a href="https://www.w3.org/TR/WCAG21/#non-text-contrast">success criterion 1.4.11 non-text contrast</a>). A black or very dark background is the best bet for color contrast using the default styling.</p>
<img src="https://htmhell.dev/images/advent2022/7/meter-contrast.png" alt="Green, yellow and red meter bars against white and black backgrounds for Safari, Chrome and Firefox." loading="lazy" width="800" height="672">
<p>Keep in mind there can be variations between operating systems and displays, as well as browsers. My machine (2017 iMac 5k retina with default calibration) produced the following results (<a href="https://docs.google.com/spreadsheets/d/1x530peUSnh5Ir_77pkmZf6yVFxK700pMqB8QdbeOZvU/edit?usp=sharing">Google sheet with hex colors and contrast ratios</a>):</p>
<ul>
<li>Black background
<ul>
<li>Chrome, Firefox, Safari - all three color passed.</li>
</ul>
</li>
<li>White background
<ul>
<li>Chrome - green and red passed, yellow failed.</li>
<li>Firefox - red passed, green and yellow failed.</li>
<li>Safari - all three colors failed.</li>
</ul>
</li>
</ul>
<p>Other items of note:</p>
<ul>
<li>Firefox provides borders that have at least 3.1 contrast ratio against a white background, but don't meet that contrast threshold with the adjacent fill color.</li>
<li>In Safari the unused portion of the bar is transparent against a dark background.</li>
<li>Using Windows High Contrast Mode the <code>&lt;meter&gt;</code> bar fill rendered using the "selected text" color regardless of whether or not it was styled.</li>
</ul>
<h2 data-sanitized-id="using-optimum-to-render-different-colors">Using <code>optimum</code> to render different colors</h2>
<p>When using a combination of <code>min</code>, <code>max</code> and <code>value</code> the bar color will be green regardless of the value. When including any combination of <code>low</code>, <code>high</code> and <code>optimum</code> the bar colors can be changed without any additional styling.</p>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meter#attr-optimum">MDN sums up using optimum</a>:</p>
<blockquote>When used with the <code>low</code> attribute and <code>high</code> attribute, it gives an indication where along the range is considered preferable. For example, if it is between the <code>min</code> attribute and the <code>low</code> attribute, then the lower range is considered preferred. The browser may color the meter's bar differently depending on whether the value is less than or equal to the optimum value.</blockquote>
<p>An example:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token comment">&lt;!-- Bar colors: yellow, green, yellow --&gt;</span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>0<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">high</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>80<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>20<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>0<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">high</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>80<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>40<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>0<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">high</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>80<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>90<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token comment">&lt;!-- Bar colors: red, yellow, green --&gt;</span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>0<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">high</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>80<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">optimum</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>85<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>20<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>0<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">high</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>80<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">optimum</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>85<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>40<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>0<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">high</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>80<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">optimum</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>85<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>90<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token comment">&lt;!-- Bar colors: green, yellow, red --&gt;</span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>0<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">high</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>80<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">optimum</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>10<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>20<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>0<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">high</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>80<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">optimum</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>10<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>40<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>0<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>20<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">high</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>80<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">optimum</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>10<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>90<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p><a href="https://codepen.io/superterrific/pen/KKRJwqW">View at CodePen</a></p>
<p>It's best to play around with your values to see how it behaves, but generally</p>
<ul>
<li>Using only <code>low</code> and <code>high</code> will render orange/amber or green.</li>
<li>Adding <code>optimum</code> can additionally render red.</li>
</ul>
<p>Daniel Aleksandersen discovered <a href="https://www.ctrl.blog/entry/html-meter-segment-boundaries.html">browsers can render the segment boundaries differently</a> depending on how they interpret the spec.</p>
<blockquote>Firefox’s implementation is consistent: the values of the attributes are excluded from the segments with the same name (exclusive). Like Firefox, Chrome and Safari exclude the <code>low</code> attribute value from the low segment. Unlike Firefox, Chrome and Safari include the <code>high</code> attribute value in the high segment (inclusive).</blockquote>
<p>There's a <a href="https://github.com/whatwg/html/issues/3520">bug filed against the spec</a> to call for clarification. In the meantime he's also <a href="https://www.ctrl.blog/entry/html-meter-segment-boundaries.html">discovered a workaround</a> if you encounter the issue.</p>
<h2 data-sanitized-id="styling">Styling</h2>
<p>Considering contrast issues, potential rendering differences or the needs of your use case you may want to style the <code>&lt;meter&gt;</code> element.</p>
<p>In 2013 <a href="https://css-tricks.com/html5-meter-element/">CSS Tricks created a comprehensive post</a> that still seems to be considered the go-to for <code>&lt;meter&gt;</code> styling. A more <a href="https://uipencil.com/2022/08/30/how-to-create-a-meter-scale-from-pure-html-html-meter-tag/">recent post at UI Pencil</a> has a straightforward bar color, shape and size example. Creating the example from that post <a href="https://codepen.io/superterrific/pen/ZEoVyKW">at CodePen</a> allowed for screenreader testing to see how styling might impact screen reader support.</p>
<img src="https://htmhell.dev/images/advent2022/7/meter-styled.png" alt="Three meter bars styled with colors different than the default colors." loading="lazy" width="568" height="466">
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>h2</span><span data-sanitized-class="token punctuation">&gt;</span></span>Battery Life<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>h2</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span>Current value = 15</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>15<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>0<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>20<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">high</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>80<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">optimum</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    15% battery remaining</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span>Current value = 59</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>59<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>0<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>20<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">high</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>80<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">optimum</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    59% battery remaining</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span>Current value = 88</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>88<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>0<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>20<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">high</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>80<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">optimum</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    88% battery remaining</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p><a href="https://codepen.io/superterrific/pen/ZEoVyKW">View at CodePen</a></p>
<ul>
<li>NVDA + Chrome styling has no effect, announces "progress bar" + value (e.g., "Current value = 15, progress bar 15").</li>
<li>NVDA + Firefox styling has no effect, announces "progress bar" + fallback text (e.g., "Current value = 15, progress bar 15% battery remaining").</li>
<li>Narrator + Edge styling has no effect, announces value as percent + meter (e.g., "Current value = 15, 15% meter").</li>
<li>VoiceOver MacOS ignores the <code>&lt;meter&gt;</code> when styled, including fallback text (e.g., "Current value = 15"). Will announce an accessible name (e.g., <code>aria-label</code>) but add "empty group".</li>
<li>VoiceOver iOS ignores the <code>&lt;meter&gt;</code> when styled, including accessible name (e.g., <code>aria-label</code>).</li>
<li>Including an accessible name had no negative impact on NVDA and Narrator.</li>
</ul>
<p>The example above includes the text labels as <code>&lt;p&gt;</code> tags. Including the value in this way worked well for VoiceOver as it only announced the text (e.g., Current value = 15). The downside of this approach is that it added a bit of verbosity for NVDA and Narrator.</p>
<h2 data-sanitized-id="use-case-examples">Use case examples</h2>
<p>The previously mentioned 2013 CSS Tricks article has a <a href="https://css-tricks.com/html5-meter-element/#aa-experiment-2-osx-style-disk-usage">disk space usage example</a> and accompanying <a href="https://codepen.io/pankajparashar/pen/ALgGqm">CodePen</a>. It's a good example of extending the <code>&lt;meter&gt;</code> element with styling while supporting people using assistive technology. The <code>&lt;meter&gt;</code> element semantically communicates the total disk usage while being styled to visually display the segments (audio, movies, photos, apps, other). If the <code>&lt;meter&gt;</code> information is not announced the adjacent text and unordered list ensures all the vital information is communicated.</p>
<p>Leslie Cohn Wein posted about a recent <a href="https://leslie.dev/posts/writing-semantic-html-even-when-you-dont-know-any-better/">budgeting use case</a> where talking through the scenario helped to clarify the semantics between <code>&lt;meter&gt;</code> and <code>&lt;progress&gt;</code>, and for her use case <code>&lt;meter&gt;</code> was the better choice.</p>
<p>Lea Verou recently posted about attempting to use the <a href="https://lea.verou.me/2022/08/on-ratings-and-meters/"><code>&lt;meter&gt;</code> element for star ratings</a>, and her explorations for creating a web component that's still a work in progress. Sven Wolfermann also created a <a href="https://codepen.io/maddesigns/pen/oQoMre">star rating example at CodePen</a> inspired by Verou's work.</p>
<h2 data-sanitized-id="should-you-use-the-lessmetergreater-element?">Should you use the <code>&lt;meter&gt;</code> element?</h2>
<p>On first glance the <code>&lt;meter&gt;</code> element might seem straightforward for accessibility given that it's a semantic element, but testing has shown the support is not uniform.</p>
<p>If you're building something for an internal team where the all of the devices, browsers and assistive technology in use are known, you're likely to be in a much better position to make the <code>&lt;meter&gt;</code> element accessible to all. If you're building for a wider audience it's tougher to ensure.</p>
<p>Given the lack of sufficient contrast against light backgrounds, styling the <code>&lt;meter&gt;</code> element with at least a 3.1 contrast ratio against the background or adjacent colors is a good approach. Styled <code>&lt;meter&gt;</code> elements have relatively good support for desktop/laptop, but VoiceOver on iOS, a <a href="https://webaim.org/projects/screenreadersurvey9/#mobilescreenreaders">popular mobile screen reader</a>, ignores the <code>&lt;meter&gt;</code> when styled.</p>
<p>Using visually hidden text instead of fallback text or accessible names presents an option that can make using the <code>&lt;meter&gt;</code> element more accessible, regardless of whether or not it's styled.</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"> <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>0<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>65<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"> <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>span</span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>visually-hidden<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>65 out of 100 items<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>span</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"> <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meter</span> <span data-sanitized-class="token attr-name">min</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>1<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">max</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>100<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">low</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>30<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">high</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>80<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">optimum</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>85<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>20<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>meter</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"> <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>span</span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>visually-hidden<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>20 centimeters long out of 100 total<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>span</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p><a href="https://codepen.io/superterrific/pen/YzvQBNK?editors=1100">View at CodePen</a></p>
<p>Above code not styled:</p>
<ul>
<li>NVDA + Chrome announces "progress bar" + value + text (e.g., "progress bar 65. 65 out of 100 items").</li>
<li>NVDA + Firefox announces "progress bar" + value + text (e.g., "progress bar 65. 65 out of 100 items").</li>
<li>Narrator + Edge announces value as a percent + "meter" + text (e.g., "65% meter. 65 out of 100 items").</li>
<li>VoiceOver + MacOS announces value as percent + "level indicator" + text (e.g., "65% level indicator. 65 out of 100 items").</li>
<li>VoiceOver + iOS announces value as percent + text (e.g., "65%. 65 out of 100 items").</li>
</ul>
<p>Above code styled:</p>
<ul>
<li>NVDA + Chrome announces "progress bar" + value + text (e.g., "progress bar 65. 65 out of 100 items").</li>
<li>NVDA + Firefox announces "progress bar" + value + text (e.g., "progress bar 65. 65 out of 100 items").</li>
<li>Narrator + Edge announces value as a percent + "meter" + text (e.g., "65% meter. 65 out of 100 items").</li>
<li>VoiceOver + MacOS announces only text (e.g., "65 out of 100 items").</li>
<li>VoiceOver + iOS announces only text (e.g., "65 out of 100 items").</li>
</ul>
<p>This approach ensures announcement for mobile VoiceOver users and provides more consistently supported announcement than fallback text, albeit at the expense of some verbosity.</p>
<p>One issue to note with this approach is that there's a pause between the <code>&lt;meter&gt;</code>'s content and visually hidden text for the combinations that announce both. This may be confusing and not achieve the goal if it's unclear that the <code>&lt;meter&gt;</code>'s content and visually hidden text are related. Testing with screen reader users would help to clarify if this approach works.</p>
<h2 data-sanitized-id="conclusion">Conclusion</h2>
<p>In 2018 <a href="https://scottaohara.github.io/a11y_styled_form_controls/">Scott O'Hara said</a> of the <code>&lt;meter&gt;</code> and <code>&lt;progress&gt;</code> elements...</p>
<blockquote>Unfortunately, neither of these elements are consistently accessible to screen readers. Styling each can actually make them even more inaccessible</blockquote>
<p>There have been improvements since his <a href="https://scottaohara.github.io/a11y_styled_form_controls/src/meter/">initial tests</a>, but there are still inconsistencies and unknowns. And styling can still render the <code>&lt;meter&gt;</code> inaccessible for VoiceOver + Safari on MacOS and iOS.</p>
<p>If you are going to use the <code>&lt;meter&gt;</code> element, use it with caution and keep these things in mind:</p>
<table>
<thead>
<tr>
<th>Screen reader + browser</th>
<th>Announces fallback text</th>
<th>Announces accessible name</th>
<th>Styling breaks announcement</th>
<th>Announces extra information based on high, low, optimum</th>
</tr>
</thead>
<tbody>
<tr>
<td>NVDA + Chrome</td>
<td>No</td>
<td>Yes</td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td>NVDA + Firefox</td>
<td>Yes</td>
<td>Yes</td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td>Narrator + Edge</td>
<td>No</td>
<td>Yes</td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td>VoiceOver + Safari MacOs</td>
<td>Yes unless styled</td>
<td>Yes including when styled</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td>VoiceOver + Safari iOS</td>
<td>Yes unless styled</td>
<td>Yes unless styled</td>
<td>Yes</td>
<td>Yes</td>
</tr>
</tbody>
</table>
<ul>
<li>Don't assume the <code>&lt;meter&gt;</code> element's semantics are uniformly supported or announced across screen readers.</li>
<li>Pay attention to contrast. When using default colors a dark background is best.</li>
<li>If you're supporting light and dark mode or themes, make sure your <code>&lt;meter&gt;</code> bar fill colors work across the board.</li>
<li>If styling, assume it will break or nullify semantic support for assistive technology and provide semantic information (e.g., value, additional labeling) using methods with broad support.</li>
<li>Accessible names (<code>aria-label</code>, <code>aria-labeledby</code>) may cause some screen readers to ignore the <code>&lt;meter&gt;</code> element content and only announce the accessible name (<a href="https://scottaohara.github.io/a11y_styled_form_controls/src/meter/">source</a> - JAWS, and potentially other screen readers not tested here).</li>
<li>As always, it's best to test with a screen reader, and if you can hire screen reader users to test, even better.</li>
</ul>
<h2 data-sanitized-id="resources">Resources</h2>
<ul>
<li><a href="https://html.spec.whatwg.org/multipage/form-elements.html#the-meter-element">HTML Spec</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meter">MDN</a></li>
<li><a href="https://scottaohara.github.io/a11y_styled_form_controls/src/meter/">Styled Meter Accessibility Tests 2018</a></li>
<li><a href="https://www.ctrl.blog/entry/html-meter-segment-boundaries.html">The HTML meter element and it's (undefined) segment boundaries</a></li>
</ul>
<h2 data-sanitized-id="special-thanks">Special thanks</h2>
<p>Many thanks to <a href="https://ericwbailey.website/">Eric Bailey</a> for reviewing this post. His thoughtful feedback notably improved the outcome and increased my understanding. And a special thank you to <a href="https://www.matuzo.at/">Manuel Matuzovic</a> for his unwavering dedication to saving us all from HTMHell.</p>


guid: https://htmhell.dev/adventcalendar/2022/6/
title: Adding Complementary Performance Data to Your Site
author: ;Manuel Matuzovic
link: https://htmhell.dev/adventcalendar/2022/6/
hash: w'��F|? MS��h��{
attributes: {"enclosures":[]}
content:
<p>Getting performance data from real users can transform assumptions about how a user experiences a site into objective, actionable information.</p>
<p>In the last two years, there has been increased awareness of web performance thanks to Google's Core Web Vitals (CWV) metrics. These metrics are great and have nearly universal application, but it can also be helpful to add information specific to your site. Fortunately, it's easier than ever to collect this data thanks to features that have made their way into browsers in recent years.</p>
<h2 data-sanitized-id="critical-landmarks">Critical Landmarks</h2>
<p>Using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/PerformanceObserver"><code>PerformanceObserver</code></a> API, you can get performance information about page navigation, in-page landmarks like how long it takes to parse the HTML, how long it takes to download and render specific resources, and it's even possible to measure server performance with the <a href="https://www.w3.org/TR/server-timing/"><code>Server-Timing</code></a> header.</p>
<p>It's possible you have a dedicated Real User Monitoring (RUM) vendor that takes care of logging this information for you, but if not, most site analytics packages allow you to define and log custom data.</p>
<p>There has been much written about <abbr title="Core Web Vitals">CWV</abbr>, but for the purpose of this article, I'll talk about data that complements <abbr title="Core Web Vitals">CWV</abbr> and make comparisons where necessary. If you want to track <abbr title="Core Web Vitals">CWV</abbr>, there is a <a href="https://github.com/GoogleChrome/web-vitals">package</a> and <a href="https://web.dev/vitals/">accompanying article</a> that covers it in detail.</p>
<p><em>Note:</em> In some cases below, I'm using a placeholder function called <code>sendToAnalytics</code> to indicate where you might want to send the data to your site analytics to get the measurements from real users. You'll need to check the docs of your specific analytics software to see how to send data for your use case.</p>
<h2 data-sanitized-id="implementation">Implementation</h2>
<p>Using <a href="https://developer.mozilla.org/en-US/docs/Web/API/PerformanceObserver/PerformanceObserver"><code>PerformanceObserver</code></a>, it's possible to get precise information about events that occur during the page lifecycle.</p>
<p>Browsers log activities, known as entries, automatically for certain things like the resource timing entry that happens when files like images are loaded or the navigation timing entry that happens when navigation occurs. Every browser implements a different set of entries. You can run <code>PerformanceObserver.supportedEntryTypes</code> in the browser's console to see what is supported in your browser.</p>
<p>It's also possible to add your own entries, which you'll see below. The ones that we'll deal with are:</p>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Performance/mark"><code>performance.mark</code></a> which records a single, named timestamp</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Performance/measure"><code>performance.measure</code></a> which calculates the difference between 2 performance marks i.e. a start and end mark.</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/PerformanceElementTiming">PerformanceElementTiming</a> - will record timing information about a specific element on the page, such as an image or text element like <code>&lt;h1&gt;</code> by using an <code>elementtiming</code> attribute on an element.</li>
</ul>
<h3 data-sanitized-id="server-timing">Server Timing</h3>
<p>The aforementioned web-vitals package has a method to track <a href="https://web.dev/ttfb/">Time to First Byte (TTFB)</a>, which is a measure of how long it takes between the initial navigation and when a response is received from the server. This is considered a backend metric because it's impacted by network latency, the database queries that are run as part of the page's construction, and server memory.</p>
<p>However, TTFB is an aggregate metric. If you want more granularity to break down where time is being spent on the backend, you can use the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server-Timing"><code>Server-Timing</code></a> HTTP header.</p>
<pre data-sanitized-class="language-js"><code data-sanitized-class="language-js"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token keyword">import</span> <span data-sanitized-class="token punctuation">{</span> sendToAnalytics <span data-sanitized-class="token punctuation">}</span> <span data-sanitized-class="token keyword">from</span> <span data-sanitized-class="token string">"./sendToAnalytics"</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line"></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token keyword">export</span> <span data-sanitized-class="token keyword">const</span> <span data-sanitized-class="token function-variable function">trackServerTiming</span> <span data-sanitized-class="token operator">=</span> <span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token parameter">threshold <span data-sanitized-class="token operator">=</span> <span data-sanitized-class="token number">200</span></span><span data-sanitized-class="token punctuation">)</span> <span data-sanitized-class="token operator">=&gt;</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token keyword">try</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token keyword">for</span> <span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token keyword">const</span> <span data-sanitized-class="token punctuation">{</span> name<span data-sanitized-class="token operator">:</span> url<span data-sanitized-class="token punctuation">,</span> serverTiming <span data-sanitized-class="token punctuation">}</span> <span data-sanitized-class="token keyword">of</span> performance<span data-sanitized-class="token punctuation">.</span><span data-sanitized-class="token function">getEntriesByType</span><span data-sanitized-class="token punctuation">(</span></span><br><span data-sanitized-class="highlight-line">      <span data-sanitized-class="token string">"navigation"</span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token punctuation">)</span><span data-sanitized-class="token punctuation">)</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">      <span data-sanitized-class="token keyword">for</span> <span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token keyword">const</span> <span data-sanitized-class="token punctuation">{</span> name<span data-sanitized-class="token punctuation">,</span> duration <span data-sanitized-class="token punctuation">}</span> <span data-sanitized-class="token keyword">of</span> serverTiming<span data-sanitized-class="token punctuation">)</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">        <span data-sanitized-class="token comment">// we only care about data beneath the threshold</span></span><br><span data-sanitized-class="highlight-line">        <span data-sanitized-class="token keyword">if</span> <span data-sanitized-class="token punctuation">(</span>duration <span data-sanitized-class="token operator">&gt;</span> threshold<span data-sanitized-class="token punctuation">)</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">          <span data-sanitized-class="token function">sendToAnalytics</span><span data-sanitized-class="token punctuation">(</span>url<span data-sanitized-class="token punctuation">,</span> name<span data-sanitized-class="token punctuation">,</span> duration<span data-sanitized-class="token punctuation">)</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">        <span data-sanitized-class="token punctuation">}</span></span><br><span data-sanitized-class="highlight-line">      <span data-sanitized-class="token punctuation">}</span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token punctuation">}</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token punctuation">}</span> <span data-sanitized-class="token keyword">catch</span> <span data-sanitized-class="token punctuation">(</span>e<span data-sanitized-class="token punctuation">)</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">    console<span data-sanitized-class="token punctuation">.</span><span data-sanitized-class="token function">error</span><span data-sanitized-class="token punctuation">(</span>e<span data-sanitized-class="token punctuation">)</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token punctuation">}</span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token punctuation">}</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line"></span></code></pre>
<h3 data-sanitized-id="head-blocking-time">Head Blocking Time</h3>
<p>As it relates to performance, the <code>&lt;head&gt;</code> of the document is especially sensitive and directly affects rendering. For example, CSS is a render blocking resource when it matches the device <code>media</code> attribute, and so is JavaScript when it lacks <code>async</code>, <code>defer</code>, or <code>type="module"</code> on the <code>&lt;script&gt;</code> tag.</p>
<p>There's even more of a performance hit when the assets are loaded from a third-party domain like Google Fonts or any of the popular JS CDNs. A page cannot render until the blocking assets in the head are downloaded, parsed, and in the case of blocking JavaScript, executed as well.</p>
<p>How much blocking code there is and where it's served from play a part in the initial render performance, but even the order of the tags matters. Harry Roberts has talked extensively about the <a href="https://www.smashingmagazine.com/2021/09/css-head-tag/">ideal order for tags in the <code>&lt;head&gt;</code></a> and even has a <a href="https://csswizardry.com/ct/">diagnostic stylesheet</a> to pinpoint issues. These resources will help remove the bottlenecks, and the PerformanceObserver will help track the before-and-after metrics.</p>
<p>This is done by setting performance marks at the start and end of the <code>&lt;head&gt;</code> and then using <code>performance.measure</code> to calculate the difference between the start and end marks.</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>head</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meta</span> <span data-sanitized-class="token attr-name">charset</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>utf-8<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meta</span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>viewport<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">content</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>width=device-width,initial-scale=1<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>title</span><span data-sanitized-class="token punctuation">&gt;</span></span>Example page<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>title</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meta</span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>description<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">content</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>A great example of performance marks<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br>  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>script</span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token script"><span data-sanitized-class="token language-javascript"><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token keyword">if</span><span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token string">'performance'</span> <span data-sanitized-class="token keyword">in</span> window<span data-sanitized-class="token punctuation">)</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">      performance<span data-sanitized-class="token punctuation">.</span><span data-sanitized-class="token function">mark</span><span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token string">'htmhell:documenthead:start'</span><span data-sanitized-class="token punctuation">)</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token punctuation">}</span></span><br>  </span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>script</span><span data-sanitized-class="token punctuation">&gt;</span></span><br>  <span data-sanitized-class="token comment">&lt;!-- ...the rest of the tags for the head. e.g. style, link, script, and meta tags.<br><span data-sanitized-class="highlight-line">  Probably many lines...</span><br>  --&gt;</span><br>  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>script</span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token script"><span data-sanitized-class="token language-javascript"><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token keyword">if</span><span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token string">'performance'</span> <span data-sanitized-class="token keyword">in</span> window<span data-sanitized-class="token punctuation">)</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">      performance<span data-sanitized-class="token punctuation">.</span><span data-sanitized-class="token function">mark</span><span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token string">'htmhell:documenthead:end'</span><span data-sanitized-class="token punctuation">)</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">      performance<span data-sanitized-class="token punctuation">.</span><span data-sanitized-class="token function">measure</span><span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token string">'htmhell:documenthead'</span><span data-sanitized-class="token punctuation">,</span> <span data-sanitized-class="token string">'htmhell:documenthead:start'</span><span data-sanitized-class="token punctuation">,</span> <span data-sanitized-class="token string">'htmhell:documenthead:end'</span><span data-sanitized-class="token punctuation">)</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token punctuation">}</span></span><br>  </span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>script</span><span data-sanitized-class="token punctuation">&gt;</span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>head</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>Sometimes third-parties add their own performance marks, so prefixing your marks as a namespace of sorts helps keep the chatter down in your analytics data. I like to follow the convention of <code>{site}:{component}:{description}</code>. That way, you can do some programmatic measurements by filtering through the groups with the naming convention.</p>
<h3 data-sanitized-id="important-elements">Important Elements</h3>
<p>There's usually a piece of content that is considered the most important. It depends on the type of site and the template for what the most important element might be. Here are some examples of what is likely to be the most important element:</p>
<ul>
<li>Media: article headline or main image.</li>
<li>E-commerce: product image on the product details page.</li>
<li>Search pages: the link for the first result.</li>
<li>Home page of a marketing site: hero image.</li>
<li>Video site: the video poster image.</li>
</ul>
<p><abbr title="Core Web Vitals">CWV</abbr> has a metric called Largest Contentful Paint (LCP), but that is the largest visual element and not necessarily the most important. Also, the <abbr title="Largest Contentful Paint">LCP</abbr> element can change based on a number of factors such as <a href="https://www.speedcurve.com/blog/element-timing-one-true-metric/">viewport size</a> or be stolen away by  prominent 3rd party content like ads or privacy consent modals.</p>
<p>Element Timing is currently only implemented in Chromium-based browsers, but it's worth tracking considering the significant market share that these browsers have, and more browsers should support it in the near future. It's as simple as adding an <code>elementtiming</code> attribute to the element you want to track.</p>
<p>According to <a href="https://wicg.github.io/element-timing/">the spec</a>, the relevant timing value depends on whether the element with the <code>elementtiming</code> attribute is an image or a text node.</p>
<p>For an image, it's the <code>loadTime</code> property that is important, while for a text node, it's the <code>renderTime</code> property that gives the relevant information.</p>
<p>This code below is responsible for logging both the head blocking time measurement we set earlier, as well as the element timing.</p>
<p>If you import the function and call <code>trackPerfMarks("htmhell")</code>, it will report all the elementtiming entries but will limit the <code>measure</code> and <code>mark</code> to <em>only</em> entries that were prefixed with <code>htmhell</code>.</p>
<pre data-sanitized-class="language-js"><code data-sanitized-class="language-js"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token keyword">import</span> <span data-sanitized-class="token punctuation">{</span> sendToAnalytics <span data-sanitized-class="token punctuation">}</span> <span data-sanitized-class="token keyword">from</span> <span data-sanitized-class="token string">"./sendToAnalytics"</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line"></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token keyword">export</span> <span data-sanitized-class="token keyword">const</span> <span data-sanitized-class="token function-variable function">trackPerfMarks</span> <span data-sanitized-class="token operator">=</span> <span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token parameter">prefix</span><span data-sanitized-class="token punctuation">)</span> <span data-sanitized-class="token operator">=&gt;</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token keyword">const</span> types <span data-sanitized-class="token operator">=</span> <span data-sanitized-class="token punctuation">[</span><span data-sanitized-class="token string">"measure"</span><span data-sanitized-class="token punctuation">,</span> <span data-sanitized-class="token string">"mark"</span><span data-sanitized-class="token punctuation">,</span> <span data-sanitized-class="token string">"element"</span><span data-sanitized-class="token punctuation">]</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line"></span><br><span data-sanitized-class="highlight-line">  types<span data-sanitized-class="token punctuation">.</span><span data-sanitized-class="token function">forEach</span><span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token parameter">type</span><span data-sanitized-class="token punctuation">)</span> <span data-sanitized-class="token operator">=&gt;</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token keyword">try</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">      <span data-sanitized-class="token keyword">new</span> <span data-sanitized-class="token class-name">PerformanceObserver</span><span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token parameter">list</span><span data-sanitized-class="token punctuation">)</span> <span data-sanitized-class="token operator">=&gt;</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">        list<span data-sanitized-class="token punctuation">.</span><span data-sanitized-class="token function">getEntries</span><span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token punctuation">)</span><span data-sanitized-class="token punctuation">.</span><span data-sanitized-class="token function">forEach</span><span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token parameter">entry</span><span data-sanitized-class="token punctuation">)</span> <span data-sanitized-class="token operator">=&gt;</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">          <span data-sanitized-class="token keyword">if</span> <span data-sanitized-class="token punctuation">(</span>type <span data-sanitized-class="token operator">===</span> <span data-sanitized-class="token string">"element"</span><span data-sanitized-class="token punctuation">)</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">            <span data-sanitized-class="token function">sendToAnalytics</span><span data-sanitized-class="token punctuation">(</span></span><br><span data-sanitized-class="highlight-line">              window<span data-sanitized-class="token punctuation">.</span>location<span data-sanitized-class="token punctuation">.</span>href<span data-sanitized-class="token punctuation">,</span></span><br><span data-sanitized-class="highlight-line">              entry<span data-sanitized-class="token punctuation">.</span>identifier<span data-sanitized-class="token punctuation">,</span></span><br><span data-sanitized-class="highlight-line">              entry<span data-sanitized-class="token punctuation">.</span>loadTime <span data-sanitized-class="token operator">||</span> entry<span data-sanitized-class="token punctuation">.</span>renderTime</span><br><span data-sanitized-class="highlight-line">            <span data-sanitized-class="token punctuation">)</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">          <span data-sanitized-class="token punctuation">}</span> <span data-sanitized-class="token keyword">else</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">            <span data-sanitized-class="token keyword">if</span> <span data-sanitized-class="token punctuation">(</span>entry<span data-sanitized-class="token punctuation">.</span>name<span data-sanitized-class="token punctuation">.</span><span data-sanitized-class="token function">indexOf</span><span data-sanitized-class="token punctuation">(</span>prefix<span data-sanitized-class="token punctuation">)</span> <span data-sanitized-class="token operator">!==</span> <span data-sanitized-class="token operator">-</span><span data-sanitized-class="token number">1</span><span data-sanitized-class="token punctuation">)</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">              <span data-sanitized-class="token keyword">let</span> value <span data-sanitized-class="token operator">=</span> entry<span data-sanitized-class="token punctuation">.</span>startTime<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line"></span><br><span data-sanitized-class="highlight-line">              <span data-sanitized-class="token keyword">if</span> <span data-sanitized-class="token punctuation">(</span>type <span data-sanitized-class="token operator">===</span> <span data-sanitized-class="token string">"measure"</span><span data-sanitized-class="token punctuation">)</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">                value <span data-sanitized-class="token operator">=</span> entry<span data-sanitized-class="token punctuation">.</span>duration<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">              <span data-sanitized-class="token punctuation">}</span></span><br><span data-sanitized-class="highlight-line">              <span data-sanitized-class="token function">sendToAnalytics</span><span data-sanitized-class="token punctuation">(</span>window<span data-sanitized-class="token punctuation">.</span>location<span data-sanitized-class="token punctuation">.</span>href<span data-sanitized-class="token punctuation">,</span> entry<span data-sanitized-class="token punctuation">.</span>name<span data-sanitized-class="token punctuation">,</span> value<span data-sanitized-class="token punctuation">)</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">            <span data-sanitized-class="token punctuation">}</span></span><br><span data-sanitized-class="highlight-line">          <span data-sanitized-class="token punctuation">}</span></span><br><span data-sanitized-class="highlight-line">        <span data-sanitized-class="token punctuation">}</span><span data-sanitized-class="token punctuation">)</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">      <span data-sanitized-class="token punctuation">}</span><span data-sanitized-class="token punctuation">)</span><span data-sanitized-class="token punctuation">.</span><span data-sanitized-class="token function">observe</span><span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">        type<span data-sanitized-class="token punctuation">,</span></span><br>        <span data-sanitized-class="token comment">/* `buffered: true` catches entries that happened<br><span data-sanitized-class="highlight-line">         * before the observer was registered, as well as future events</span><br>         */</span><br><span data-sanitized-class="highlight-line">        buffered<span data-sanitized-class="token operator">:</span> <span data-sanitized-class="token boolean">true</span></span><br><span data-sanitized-class="highlight-line">      <span data-sanitized-class="token punctuation">}</span><span data-sanitized-class="token punctuation">)</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token punctuation">}</span> <span data-sanitized-class="token keyword">catch</span> <span data-sanitized-class="token punctuation">(</span>e<span data-sanitized-class="token punctuation">)</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">      console<span data-sanitized-class="token punctuation">.</span><span data-sanitized-class="token function">error</span><span data-sanitized-class="token punctuation">(</span>e<span data-sanitized-class="token punctuation">)</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token punctuation">}</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token punctuation">}</span><span data-sanitized-class="token punctuation">)</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token punctuation">}</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line"></span></code></pre>
<h2 data-sanitized-id="final-considerations">Final Considerations</h2>
<p>You can see a demo of how all of this is put together in this <a href="https://codesandbox.io/s/htmhell-performance-0wr20r">CodeSandbox demo</a>. If you open your console, you will see the events getting recorded by our mock function. Unfortunately, CodeSandbox doesn't include the Server-Timing header, but if it did, it would pick up the data.</p>
<p>With application-specific data, you can use it to help form a complete picture of how users are experiencing a site. This can be used to inform your decisions on where to focus performance efforts or how to build a case for performance.</p>
<p>It's worth noting that I include the part of the script that registers the PerformanceObserver and sends the data to analytics from a deferred script file i.e. one with the <code>defer</code> attribute or <code>type="module"</code>, meaning. I might miss some data this way from visitors who didn't stick around long enough for the script to run, but I'd rather do that then load the script in a non-deferred way and have it block rendering.</p>
<p>This type of data is a permanent fixture in my analytics reporting because it helps to track performance over time.</p>


guid: https://htmhell.dev/adventcalendar/2022/7/
title: Meaningful labels using ARIA – or not.
author: ;Manuel Matuzovic
link: https://htmhell.dev/adventcalendar/2022/7/
hash: + 7r׶Ɣ�Q�ԣ��a
attributes: {"enclosures":[]}
content:
<p>If I had a dollar for every time I've had to tell someone to remove an <code>aria-label</code> from an interactive control that has actual visible text, I could have bought Twitter! As a former developer and current accessibility consultant, it is my sincere hope that by reading this article, developers unfamiliar with or unsure about this topic will have a better understanding of the differences between <code>aria-label</code>, <code>aria-labelledby</code>, and <code>aria-describedby</code>.</p>
<p>Semantic HTML elements convey meaning - role and state - to browsers and assistive technologies. Whenever you <strong>can</strong> use an appropriate native HTML element, you <strong>should</strong> do so. For example, using a <code>&lt;button&gt;</code>, instead of using a generic element such as a <code>&lt;div&gt;</code> and then adding ARIA roles and states and properties and JavaScript functions and CSS to make it look and behave like a button, is a much better way to code. In fact, the <a href="https://www.w3.org/TR/using-aria/#rule1">First Rule of ARIA</a> is: <strong>Use HTML</strong>. (<a href="https://twitter.com/stevefaulkner/status/1433774405797257222">Credit for that paraphrase</a>.)</p>
<h2 data-sanitized-id="when-should-i-use-aria-to-label-something?">When should I use ARIA to label something?</h2>
<p>Using this <a href="https://adrianroselli.com/2020/01/my-priority-of-methods-for-labeling-a-control.html">priority of methods for labelling a control</a> list, first ask yourself, “do I really need to use ARIA here?” That is, can you add visible text to your element or programmatically associate existing text using native HTML semantics? There are multiple ways to do this; here are a few.</p>
<h3 data-sanitized-id="html-lesslabelgreater-tag">HTML <code>&lt;label&gt;</code> tag</h3>
<p>Use the <code>for</code> attribute to tie a <code>&lt;label&gt;</code> to its input.</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fname<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>First name:<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>text<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fname<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>   </span><br><span data-sanitized-class="highlight-line"></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>lname<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Last name:<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>text<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>lname<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span></code></pre>
<h3 data-sanitized-id="html-lessfieldsetgreater-and-lesslegendgreater-tags">HTML <code>&lt;fieldset&gt;</code> and <code>&lt;legend&gt;</code> tags</h3>
<p>Use <code>&lt;fieldset&gt;</code> and <code>&lt;legend&gt;</code> tags to group and label radio button and checkbox sets.</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>fieldset</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>legend</span><span data-sanitized-class="token punctuation">&gt;</span></span>What is your favorite breakfast food?<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>legend</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line"></span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>radio<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>waffles<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fav_breakfast<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>waffles<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>waffles<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Waffles<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"></span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>radio<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>pancakes<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fav_breakfast<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>pancakes<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>pancakes<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Pancakes<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"></span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>radio<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>leftover_pizza<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fav_breakfast<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>leftover_pizza<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>pizza<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Leftover Pizza<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>fieldset</span><span data-sanitized-class="token punctuation">&gt;</span></span> </span></code></pre>
<h3 data-sanitized-id="html-alt-attribute-for-images">HTML <code>alt</code> attribute for images</h3>
<p>Use meaningful <code>alt</code> text for images, particularly when the image is the only content for a link or a button. The <code>alt</code> text in the next example is much more meaningful to a screen reader user for understanding the purpose of the link than simply describing the bags of money in the image would be.</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>a</span> <span data-sanitized-class="token attr-name">href</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>/win-the-lottery<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>img</span> <span data-sanitized-class="token attr-name">src</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>bags-of-money.png<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">alt</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>How to win the lottery. Heaping bags of money to help prove the point.<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>a</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span></code></pre>
<p>ARIA should be used only to enhance HTML when necessary, not to "fix" bad HTML. That being said, there are times when it may be necessary to clarify or supplement labeling for various elements in order to make them more accessible for users of assistive technologies such as screen reading or voice control software.</p>
<p>There are some great tips on creating effective and user-friendly names in the tutorial <a href="https://hidde.blog/better-accessible-names/">better accessible names</a> that apply to all methods of labeling.</p>
<h2 data-sanitized-id="should-i-use-aria-label-or-aria-labelledby?">Should I use <code>aria-label</code> or <code>aria-labelledby</code>?</h2>
<p><abbr title="too long, didn't read">TLDR</abbr>:</p>
<ul>
<li>If text for the label is available somewhere on the page, use <code>aria-labelledby</code>.</li>
<li>If text for the label doesn't exist on the page, use <code>aria-label</code>.</li>
</ul>
<p>The <code>aria-label</code> attribute accepts a string of text as its value. The <code>aria-labelledby</code> attribute takes the value of one or more <code>id</code> attributes. It's especially important to understand that <strong>both <code>aria-label</code> and <code>aria-labelledby</code> replace any existing label content</strong> for assistive technologies. Let's go over some examples.</p>
<h3 data-sanitized-id="appropriate-uses-of-aria-label">Appropriate uses of <code>aria-label</code></h3>
<p>Interactive elements with informative icons or icon fonts that don't have accompanying text all need textual names to be accessible. Some examples are links to social media pages and icon-only buttons such as Print, Download, or Info. The <code>aria-label</code> attribute works great for these situations. Here, an icon is displayed using CSS for an otherwise empty link:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>a</span> <span data-sanitized-class="token attr-name">href</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>...<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>icon-facebook social-icon<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">aria-label</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Facebook page<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>a</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>You know that "X" button in the corner of a modal? Please, give it an <code>aria-label</code>! The following example will overwrite the visible text content of "X" and announce as "Close," which definitely makes more sense than hearing "X".</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>button</span> <span data-sanitized-class="token attr-name">aria-label</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Close<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>X<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>button</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>In some cases you could instead provide <code>alt</code> text that would create an appropriate button or link label (and get bonus points for following ARIA Rule #1!).</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>button</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>img</span> <span data-sanitized-class="token attr-name">src</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>system-icon-circle-x.png<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">alt</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Close<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>button</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span></code></pre>
<p>When there are multiple navigation areas on a page, adding an <code>aria-label</code> to each can help a screen reader user differentiate between the regions and better understand where they are on the page. Don't include the word "navigation" as that is already announced via the <code>&lt;nav&gt;</code> role.</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>nav</span> <span data-sanitized-class="token attr-name">aria-label</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Primary<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span> ... <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>nav</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>nav</span> <span data-sanitized-class="token attr-name">aria-label</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Breadcrumbs<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span> ... <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>nav</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>div</span> <span data-sanitized-class="token attr-name">role</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>navigation<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">aria-label</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Footer<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span> ... <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>div</span><span data-sanitized-class="token punctuation">&gt;</span></span>`   </span></code></pre>
<p>Make sure your <code>aria-label</code> value is meaningful. In this next example, the info button label essentially just describes the button's icon:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token comment">&lt;!-- don't do this --&gt;</span>  </span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span>This makes me want to absquatulate.  </span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>button</span> <span data-sanitized-class="token attr-name">aria-label</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>question mark<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line">		<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>i</span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fa fa-question-circle<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>i</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>button</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span></code></pre>
<p>A much better solution would be to provide relevant content about what the info button does or why it's here:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span>This makes me want to absquatulate.  </span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>button</span> <span data-sanitized-class="token attr-name">aria-label</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>What does absquatulate mean?<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line">		<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>i</span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fa fa-question-circle<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>i</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>button</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<h3 data-sanitized-id="appropriate-uses-of-aria-labelledby">Appropriate uses of <code>aria-labelledby</code></h3>
<p>When suitable text for a label already exists elsewhere on the page, <code>aria-labelledby</code> is the preferred method for labeling (if you must use ARIA). Multiple <code>id</code> values from other elements are separated by a space within the <code>aria-labelledby</code>'s value to concatenate a single string of text.</p>
<p>Suppose you have a series of news articles on a page, and each article has a link that says "Read more." You can use <code>aria-labelledby</code> to add more context in order to differentiate between these generic links. Since <code>aria-labelledby</code> will overwrite the visible text content of the link, you'll need to add the "Read more" text back in as well.</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>h2</span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>article1-heading<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>All About Dragons<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>h2</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span>I like dragons. Blah blah blah blah blah.<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line">	<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>a</span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>article1-read-more<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">aria-labelledby</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>article1-read-more article1-heading<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Read more<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>a</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span></code></pre>
<p>This will result in the link being announced as "Read more All About Dragons." You could go one step better and <a href="https://www.nngroup.com/articles/learn-more-links/">rewrite those "Read more" links to be more descriptive for everyone</a>.</p>
<h2 data-sanitized-id="when-should-i-skip-aria-for-labeling?">When should I skip ARIA for labeling?</h2>
<p>As has been noted by <a href="https://www.tpgi.com/short-note-on-aria-label-aria-labelledby-and-aria-describedby/">Léonie Watson</a>, <a href="https://html5accessibility.com/stuff/2020/11/07/not-so-short-note-on-aria-label-usage-big-table-edition/">Steve Faulkner</a>, <a href="https://eevis.codes/blog/2021-11-29/aria-label-is-not-always-the-answer/">Eevis</a> and many others, these attributes do not work on every element. These labeling attributes are intended for:</p>
<ul>
<li>interactive elements</li>
<li>structural elements with landmark roles</li>
<li>widgets with explicit roles</li>
</ul>
<p>Check out this <a href="https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/#x5-6-accessible-name-guidance-by-role">handy chart of ARIA roles and their requirements for naming</a>.</p>
<p>Adding an <code>aria-label</code> will overwrite any visible text label that already exists, and adding an <code>aria-labelledby</code> will overwrite any visible text <em>AND</em> any <code>aria-label</code> provided. In general, you don't want to add <code>aria-label</code> when an appropriate visible text label already exists.</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>a</span> <span data-sanitized-class="token attr-name">href</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>about/<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">aria-label</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>About Us<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>About Us<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>a</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>At first glance, this may seem harmless and it won't throw an error in automated or likely even manual accessibility testing, but what about when your company goes international? You're setting your future-self up for extra work and more headaches when that redundant non-visible label doesn't get translated or updated.</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>a</span> <span data-sanitized-class="token attr-name">href</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>about/<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">aria-label</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>About Us<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Sobre Nosotros<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>a</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>Never, ever do this:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>button</span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>run-button-1<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">aria-label</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Customize Report<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Run Report<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>button</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>Sighted users will see the button's visible text label of "Run Report", but screen reader users will hear the button's accessible name of "Customize Report". Presumably "Run" and "Customize" are two different actions!</p>
<p>The problem in the previous example is not limited to screen reader users. Someone using voice control software might say "Run Report" to activate the control, but nothing will happen since that's not the accessible name. Voice control users will have to find a workaround when they need to perform the "Run" action that this button visibly indicates.</p>
<p>The following examples show some additional inappropriate uses of <code>aria-label</code>; you may as well save yourself some coding keystrokes and time spent debugging, by <strong>not</strong> doing any of the following bad examples.</p>
<h3 data-sanitized-id="non-interactive-elements">Non-interactive elements</h3>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>div</span> <span data-sanitized-class="token attr-name">aria-label</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Product Group<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>...<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>div</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>Don't put <code>aria-label</code> on a <code>&lt;div&gt;</code> or other non-interactive element without an explicit role; it does nothing but create tech debt.</p>
<h3 data-sanitized-id="decorative-images">Decorative images</h3>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>img</span> <span data-sanitized-class="token attr-name">src</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>decorative-image.jpg<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">aria-label</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span><span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>An empty <code>aria-label</code> attribute is not the same as an empty <code>alt</code> attribute. Use an empty <code>alt</code> attribute (<code>alt=""</code>) for decorative images.</p>
<h3 data-sanitized-id="prohibited-roles">Prohibited roles</h3>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>p</span> <span data-sanitized-class="token attr-name">aria-label</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Causes of eye twitching<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span> ... <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>HTML elements whose implicit roles prohibit the use of <code>aria-label</code> or <code>aria-labelledby</code> are listed in the <a href="https://www.w3.org/TR/wai-aria-1.2/#namefromprohibited">current WAI-ARIA specifications</a>.</p>
<h2 data-sanitized-id="what-about-aria-describedby?">What about <code>aria-describedby</code>?</h2>
<p>According to the <a href="https://www.w3.org/TR/wai-aria-1.1/#aria-describedby">WAI-ARIA specification for aria-describedby</a>, "a label should be concise, where a description is intended to provide more verbose information." Any <code>aria-describedby</code> content is announced by screen reading software after the element's label is read out.</p>
<p>The <code>aria-describedby</code> attribute should be used to provide supplemental content to an element's label – in addition to the label – rather than to label it directly. Examples of this might be to provide "helper text" about input format or other requirements when completing a form field, or to associate an error message with a specific input.</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>textbox-1<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Date<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>text<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>textbox-1<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">aria-describedby</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>description-1<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>span</span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>description-1<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Use mm/dd/yyyy format<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>span</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span></code></pre>
<p>The use of <code>aria-describedby</code> in this example will let all users know the format of the date to enter in this text input. This will announce to a screen reader user when focus is placed on the form field.</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>username<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Username<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>text<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>username<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">aria-describedby</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>username-error<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>span</span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>username-error<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Username is required<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>span</span><span data-sanitized-class="token punctuation">&gt;</span></span>  </span></code></pre>
<p>In this example, <code>aria-describedby</code> will programmatically associate the error message with the text input field, which allows screen reader users to hear the error message when the form field is focused. Sighted users will see the error message next to the text input field when it appears.</p>
<h2 data-sanitized-id="no-aria-is-better-than-bad-aria!">No ARIA is better than bad ARIA!</h2>
<p>If in doubt, leave it out! Unfortunately, it's too common to find seemingly well-intentioned ARIA labels that actually make things worse for folks using assistive technologies. Meaningful and accurate labels can benefit everyone, including screen reader users, voice control users, users with cognitive issues, and all other users!</p>
<p>Screen reader users don't need "extra" instructions like "click here to activate the button" or "extra" information such as "this is a checkbox" so don't add this type of content into element labels. ARIA labels are only available to browsers and screen reading software, and can cause frustration and extra work for a voice control user when a visible label that doesn't match the accessible name. Generally speaking, don't add labels using ARIA if it provides a different user experience to a particular user group. Don't treat users with a disability differently than you would treat other users.</p>
<p>If something is important enough to add using ARIA, consider whether it should be added for all users. <a href="https://ericwbailey.website/published/aria-label-is-a-code-smell/">Overuse or misuse of the <code>aria-label</code> attribute can be indicative of larger problems</a> within a code base or development processes. There is more than one way to write accessible code, but please be judicious in your use of ARIA for labeling purposes and just use native semantic HTML whenever possible.</p>
<h2 data-sanitized-id="resources-for-further-reading">Resources for further reading</h2>
<ul>
<li><a href="https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/">ARIA Authoring Practices Guide (APG): Providing Accessible Names and Descriptions</a></li>
<li><a href="https://www.w3.org/TR/accname-1.2/#mapping_additional_nd_te">Accessible Name and Description Computation</a></li>
<li><a href="https://www.w3.org/TR/html-aria/#docconformance-naming">Requirements for use of ARIA attributes to name elements</a></li>
<li><a href="https://www.w3.org/TR/html-aria/">ARIA in HTML</a></li>
<li><a href="https://www.a11yproject.com/checklist/">The A11Y Project Checklist</a></li>
</ul>
<h2 data-sanitized-id="one-last-thing">One last thing</h2>
<p>I want to express my sincere appreciation to <a href="https://ericwbailey.website/">Eric Bailey</a> for his excellent editorial suggestions on this article, and to <a href="https://www.matuzo.at/">Manuel Matuzovic</a> for putting this whole thing together (again!). Thank you both!</p>


guid: https://htmhell.dev/adventcalendar/2022/8/
title: Improving SEO without knowing where to start
author: ;Manuel Matuzovic
link: https://htmhell.dev/adventcalendar/2022/8/
hash: d �)6��.؇��%VW�
attributes: {"enclosures":[]}
content:
<h2 data-sanitized-id="summary">Summary</h2>
<ul>
<li><span data-sanitized-id="s1"><a href="https://htmhell.dev/adventcalendar/2022/8/#part1">Introduction</a></span></li>
<li><span data-sanitized-id="s2"><a href="https://htmhell.dev/adventcalendar/2022/8/#part2">What is SEO ?</a></span></li>
<li><span data-sanitized-id="s3"><a href="https://htmhell.dev/adventcalendar/2022/8/#part3">Web quality with Opquast</a></span></li>
<li><span data-sanitized-id="s4"><a href="https://htmhell.dev/adventcalendar/2022/8/#part4">SEO-related Opquast rules</a></span></li>
<li><span data-sanitized-id="s5"><a href="https://htmhell.dev/adventcalendar/2022/8/#part5">Conclusion</a></span></li>
</ul>
<h2 data-sanitized-id="introduction-↑"><span data-sanitized-id="part1">Introduction <a title="back to the summary" href="https://htmhell.dev/adventcalendar/2022/8/#s1">↑</a></span></h2>
<p>Colleagues sometimes ask me: “<em>Hey Alex, I would like to learn a bit about search engine optimisation (SEO) but I don't really know where to start. Do you have tips for me?”</em>. Well, it's not surprising: like accessibility, sustainability and environment, or performance, SEO is a big topic.</p>
<p>I usually answer: “<em>It's awesome that you want to dig into this. SEO is also a significant part of UX, and more globally of web quality assurance. Listen, I'm not a SEO expert but I know a solid start: these are the Opquast rules. If you apply them carefully, you will do better than most other websites.</em>”</p>
<p>In this article, first I would like to describe shortly what SEO means, then present what Opquast is, and finally explain the benefits of some Opquast's SEO rules.</p>
<p>Disclaimer: Opquast is a society. I am neither an employee nor an affiliate.</p>
<h2 data-sanitized-id="what-is-seo-?-↑"><span data-sanitized-id="part2">What is SEO ? <a title="back to the summary" href="https://htmhell.dev/adventcalendar/2022/8/#s2">↑</a></span></h2>
<p><strong>SEO</strong> stands for <strong>S</strong>earch <strong>E</strong>ngine <strong>O</strong>ptimisation. It comprises <strong>improving the visibility</strong> of a page, a site, an application in search engine results pages (abbreviated <strong>SERP</strong>). Being positioned on the first page is obviously a good thing for the owner of a site, but it's also about helping search and indexing tools to extract content efficiently, helping users find your content, improving the visual and vocal reproduction of search results to users.</p>
<p>Many people say <em>“SEO is a marathon, not a sprint”</em>, and they're right. As Frederick O’Brien wrote in his article <a href="https://www.smashingmagazine.com/smashing-guide-search-engine-optimization/#playing-the-long-game">A Smashing Guide To The World Of Search Engine Optimization</a> on Smashing Magazine:</p>
<blockquote>Implementing best practice can produce immediate results, but long-term performance requires long-term maintenance.</blockquote>
<p>We could also establish that SEO is about getting as close as possible to the “<em>requirements</em>” of Google and its Page Rank calculation algorithm, but I suggest you don't bother too much with that, especially since the statements of SEO agencies, official communication from Google, and engineers at Google can sometimes contradict each other.</p>
<p>SEO is cool because <strong>it makes developers and designers care about web quality</strong> (I personally prefer this term rather than UX). Long ago, SEO strategies were mostly about accumulating backlinks (regardless of the quality) and putting important keywords everywhere.</p>
<p>Things have fortunately changed. Today, search engines will favor sites which care about users:</p>
<ul>
<li><strong>Content:</strong>
<ul>
<li>both in style (spelling, grammar, freshness of content, consistency between titles, content and keywords)</li>
<li>and substance (relevance, reliability, veracity, completeness)</li>
</ul>
</li>
<li><strong>Netlinking:</strong> quality backlinks</li>
<li><strong>Performance:</strong> <em>“Hello Core Web Vitals”</em><sup data-sanitized-id="sup1"><a href="https://htmhell.dev/adventcalendar/2022/8/#ref1" aria-describedby="footnote-label">[1]</a></sup></li>
<li><strong>Responsiveness:</strong> today, more than half of search queries now come from mobile devices</li>
<li><strong>Semantics:</strong> a well-structured and intelligently designed site in HTML is easier to browse by an indexing robot, informations are extracted in a clearer way</li>
<li><strong>Accessiblity:</strong> (although it's not a direct ranking factor): always a good thing to remember, accessibility means that people with disabilities can perceive, understand, navigate, contribute and interact with the web<sup data-sanitized-id="sup2"><a href="https://htmhell.dev/adventcalendar/2022/8/#ref2" aria-describedby="footnote-label">2</a></sup></li>
<li><strong>Security:</strong> HTTPS, protection from XSS, tracking, info leaks, etc.</li>
</ul>
<h2 data-sanitized-id="web-quality-with-opquast-↑"><span data-sanitized-id="part3">Web quality with Opquast <a title="back to the summary" href="https://htmhell.dev/adventcalendar/2022/8/#s3">↑</a></span></h2>
<p><a href="https://www.opquast.com/en/">Opquast</a> is a French pioneering company in web quality assurance, focused on “<em>Making the web better</em>”. Opquast is well-known in France for having created <a href="https://checklists.opquast.com/en/web-quality-assurance/">The Web Quality Assurance Checklist</a> (under open CC-BY-SA license, available in English, French and Spanish), a list of 240 rules to improve your sites and take better care of your users. Opquast ensures that each of these 240 rules is written in such a way that they are:</p>
<ul>
<li><strong>Transversal:</strong> they are understandable by everyone (developer, designer, dev ops, community manager, marketing manager, sales, web editor, project manager, etc.)</li>
<li><strong>Universal:</strong> they are the subject of consensus in consultation with a broad community of experts, agencies, companies and higher education</li>
<li><strong>Sustainable:</strong> they are made to last over time</li>
<li>easily <strong>Verifiable</strong></li>
<li><strong>Useful</strong> for users</li>
<li><strong>Realistic</strong></li>
</ul>
<p>These rules cover a wide range of topics (security, links, personal information, performance, navigation, images, forms, newsletters, structure, e-commerce, etc.).</p>
<p data-sanitized-class="code-label">Some examples:</p>
<ul>
<li><a href="https://checklists.opquast.com/en/web-quality-assurance/the-period-of-validity-and-conditions-of-special-offers-and-promotions-are-indicated">Rule n° 39</a> - The period of validity and conditions of special offers and promotions are indicated</li>
<li><a href="https://checklists.opquast.com/en/web-quality-assurance/it-is-possible-to-unsubscribe-from-newsletters-from-the-website">Rule n° 171</a> - It is possible to unsubscribe from newsletters from the website</li>
<li><a href="https://checklists.opquast.com/en/web-quality-assurance/accounts-can-be-created-without-the-need-to-use-a-third-party-identification-system">Rule n° 16</a> - Account creation is possible without the need to use a third-party identification system.</li>
</ul>
<p>Among these 240 rules, 37 are SEO-related (you'll notice that some rules cover several topics at once) and I want to show you some of them.</p>
<h2 data-sanitized-id="seo-related-opquast-rules-↑"><span data-sanitized-id="part4">SEO-related Opquast rules <a title="back to the summary" href="https://htmhell.dev/adventcalendar/2022/8/#s4">↑</a></span></h2>
<h3 data-sanitized-id="describe-information-about-the-page">Describe information about the page</h3>
<blockquote data-sanitized-class="highlight"><a href="https://checklists.opquast.com/en/web-quality-assurance/each-pages-source-code-contains-metadata-that-describe-the-content">Rule n° 3</a> - Each page’s source code contains metadata that describes the content.</blockquote>
<p>Thanks to <code>meta</code> tags, search engines can provide a short description of the page to users in search result pages (SERP). (Besides, it can be automatically displayed when you share a link on social networks).</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>meta</span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>description<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">content</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>information about the page here<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>If you omit it, you let search engines choose the description for you (and that's rarely a good thing).</p>
<h3 data-sanitized-id="identify-the-site-and-its-content">Identify the site and its content</h3>
<blockquote data-sanitized-class="highlight"><a href="https://checklists.opquast.com/en/web-quality-assurance/each-page-provides-a-title-that-enables-one-to-identify-the-site">Rule n° 97</a> - Each page provides a title that enables one to identify the website.</blockquote>
<blockquote data-sanitized-class="highlight"><a href="https://checklists.opquast.com/en/web-quality-assurance/each-page-provides-a-title-that-enables-one-to-identify-its-content">Rule n° 98</a> - Each page provides a title that enables one to identify its content.</blockquote>
<p>Text in the <code>title</code> element is really important, it's used everywhere: tabs, bookmarks, favorites, homescreen phone, screen readers, share preview, social media. And in <abbr title="search engine results page">SERP</abbr> obviously.</p>
<p><img src="https://htmhell.dev/images/advent2022/16/bk-fail-98.jpg" alt='Screenshot of a search result showing the title and description from the Burger King "Customer Support" page. The title provided is just "Burger King". The description is "Discover our menu and order delivery or pick up from a Burger King near you. Burger King. Sign Up. Shopping cart preview $0.00 Cart total"'></p>
<p>In the <code>title</code> element from the "Customer Support" page of the Burger King website, the text is just "Burger King". The site is identified but not the content (Notice how it fails rule n° 3).</p>
<h3 data-sanitized-id="alternative-text">Alternative text</h3>
<blockquote data-sanitized-class="highlight"><a href="https://checklists.opquast.com/en/web-quality-assurance/each-decorative-image-has-an-appropriate-text-alternative">Rule n° 111</a> - Each decorative image has an appropriate text alternative.</blockquote>
<p>If an image doesn't provide any important information for the good understanding of the content, simply add <code>alt=""</code> to it. Otherwise, you let this sort thing happen:</p>
<p><img src="https://htmhell.dev/images/advent2022/16/casto-fail-111.jpg" alt='Screenshot of a search result showing the title and description from the Castorama "Find a store" page. The title provided is just "Trouver un magasin - Castorama". The description is "Tous les magasins Castorama. Auvergne-Rhone-Alpes. chevron right Bourg-en-bresse; chevron right Bourgoin-jallieu; chevron right Bron; chevron right ..."'></p>
<blockquote data-sanitized-class="highlight"><a href="https://checklists.opquast.com/en/web-quality-assurance/each-information-carrying-image-has-an-appropriate-text-alternative">Rule n° 113</a> - Each information-carrying image has an appropriate text alternative.</blockquote>
<p>When an image contains textual and/or visual information useful to understanding the content, it must be described in the <code>alt</code> attribute. As you saw in the example of rule n° 97, alternative texts are also taken into account.</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>div</span> <span data-sanitized-class="token attr-name">class</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>f-incentiveBox__content<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>img</span> <span data-sanitized-class="token attr-name">src</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>/brutX-logo-v2.png<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">	</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>b</span><span data-sanitized-class="token punctuation">&gt;</span></span>1 MOIS OFFERT<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>b</span><span data-sanitized-class="token punctuation">&gt;</span></span> puis 4,99€/mois</span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>div</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>This piece of HTML is from <a href="https://www.fnac.com/Ecouteurs-sans-fil-Sony-True-Wireless-WF1000XM4B-avec-reduction-de-bruit-Noir/a15967460/w-4">a product page on fnac.com</a>. The product is on sale with a one-month free offer at a video streaming platform (BrutX). But if you are an indexing robot (or a screen reader user), you wouldn't know because the <code>alt</code> attribute is missing.</p>
<h3 data-sanitized-id="links">Links</h3>
<blockquote data-sanitized-class="highlight"><a href="https://checklists.opquast.com/en/web-quality-assurance/each-image-link-has-an-appropriate-text-alternative">Rule n° 112</a> - Each image link has an appropriate text alternative.</blockquote>
<p>Users hate unlabeled links. Indexing robots too. They will find this content irrelevant and hard to reference.</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>a</span> <span data-sanitized-class="token attr-name">href</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>/actualite-sup_veto_formation_asv<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">target</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>_blank<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>img</span> <span data-sanitized-class="token attr-name">src</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>/imageDiplomeo032022.jpg<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">alt</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span><span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>								</span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>a</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>This piece of HTML is from <a href="https://supveto.com/">supveto.com</a>. There is an <code>alt</code> attribute, but it's empty and it doesn't provide the link with an accessible name.</p>
<blockquote data-sanitized-class="highlight"><a href="https://checklists.opquast.com/en/web-quality-assurance/all-hyperlinks-internal-to-the-site-are-valid">Rule n° 147</a> - All links internal to the website are valid.</blockquote>
<p>I said indexing robots hate unlabeled links; they hate broken links even more. You might not be able to check external links regularly but regarding internal links, try to set up a routine (automated or not) to check their validity.</p>
<h3 data-sanitized-id="a-bit-of-semantics">A bit of semantics</h3>
<blockquote data-sanitized-class="highlight"><a href="https://checklists.opquast.com/en/web-quality-assurance/each-pages-source-code-specifies-the-contents-main-language">Rule n° 125</a> - Each page’s source code indicates the content’s main language.</blockquote>
<p>Another easy way to help indexing robots crawl your content is to fill the <code>lang</code> attribute at the root of the document. Because the natural language of a page isn't always identifiable by tools as screen readers, translation tools, indexing robots, etc.</p>
<p data-sanitized-class="code-label">Example for English:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>html</span> <span data-sanitized-class="token attr-name">lang</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>en<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="code-label">You can also indicate a temporary change of language inside content:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>html</span> <span data-sanitized-class="token attr-name">lang</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>en<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  ...</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>body</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    ...</span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>ul</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">      ...</span><br><span data-sanitized-class="highlight-line">      <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>li</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">        <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>a</span> <span data-sanitized-class="token attr-name">href</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>path/to/german/content<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">          <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>span</span> <span data-sanitized-class="token attr-name">lang</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>de<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Deutsch<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>span</span><span data-sanitized-class="token punctuation">&gt;</span></span> (German)</span><br><span data-sanitized-class="highlight-line">        <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>a</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">      <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>li</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">      <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>li</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">        <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>a</span> <span data-sanitized-class="token attr-name">href</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>path/to/danish/content<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">          <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>span</span> <span data-sanitized-class="token attr-name">lang</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>da<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Dansk<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>span</span><span data-sanitized-class="token punctuation">&gt;</span></span> (Danish)</span><br><span data-sanitized-class="highlight-line">        <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>a</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">      <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>li</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">      ...</span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>ul</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>body</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>html</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>Available values are listed on <a href="https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry">iana.org</a>.</p>
<blockquote data-sanitized-class="highlight"><a href="https://checklists.opquast.com/en/web-quality-assurance/the-date-of-publication-or-update-of-the-contents-is-made-available-in-a-programmatic-form">Rule n° 224</a> - The date of publication or update of the contents is made available in a programmatic form.</blockquote>
<p>I always recommend showing a publication date on content pages. It allows users to put what they read into context (reading an article from 2007 is not the same as reading an article from 2022).</p>
<p>Indexing robots also appreciate having a date, even more when it's explicit. See some examples below:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line">Updated on <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>time</span> <span data-sanitized-class="token attr-name">datetime</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>2022-06-12<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>June 12<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>time</span><span data-sanitized-class="token punctuation">&gt;</span></span>.</span><br><span data-sanitized-class="highlight-line">Published on <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>time</span> <span data-sanitized-class="token attr-name">datetime</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>2022-09-27<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Sep 27, 2022<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>time</span><span data-sanitized-class="token punctuation">&gt;</span></span>.</span><br><span data-sanitized-class="highlight-line">The event starts at <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>time</span> <span data-sanitized-class="token attr-name">datetime</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>20:00<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>8pm<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>time</span><span data-sanitized-class="token punctuation">&gt;</span></span>.</span></code></pre>
<p>More examples about this format on <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/time#valid_datetime_values">developer.mozilla.org</a> and infos on <a href="https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#dates-and-times">html.spec.whatwg.org</a>.</p>
<blockquote data-sanitized-class="highlight"><a href="https://checklists.opquast.com/en/web-quality-assurance/each-pages-content-is-organized-according-to-a-hierarchical-structure-of-headings-and-sub-headings">Rule n° 227</a> - Each page’s content is organized according to a hierarchical structure of headings and sub-headings.</blockquote>
<p>Headings are a truly big topic. They are very helpful for users and assistive technologies to apprehend the structure of a page and navigate it. They are also useful for indexing tools because they help them understand what should be considered important. Thus:</p>
<ul>
<li>don't use too long headings.</li>
<li>don't skip levels (for example, an <code>h3</code> must not be followed by an <code>h5</code> or <code>h6</code>).</li>
<li>don't use <code>hx</code> only for visual purposes (use CSS instead)</li>
<li>don't use too many headings (if everything is important, nothing is).</li>
</ul>
<p><img src="https://htmhell.dev/images/advent2022/16/nike-fail-227.jpg" alt="Headings structure of nike.com/fr containing duplicate headings and holes in the structure"></p>
<p>The structure would benefit from being clearer and more relevant here, especially the multiple headings “Nike Sportwear” are really confusing.</p>
<h3 data-sanitized-id="pdf">PDF</h3>
<p>Indexing robots crawl PDF documents as well. You can access a PDF document directly from a <abbr title="search engine results page">SERP</abbr>.</p>
<blockquote data-sanitized-class="highlight"><a href="https://checklists.opquast.com/en/web-quality-assurance/the-text-of-internal-pdf-documents-can-be-selected">Rule n° 233</a> - The text of internal PDF documents can be selected.</blockquote>
<p>Not being selectable means that the content of the PDF cannot be crawled (in addition to not being able to be copied, searchable, clickable, translatable, vocalizable). Scanned document are a pain for users, for indexing robots too.</p>
<blockquote data-sanitized-class="highlight"><a href="https://htmhell.dev/adventcalendar/2022/8/(https://checklists.opquast.com/en/web-quality-assurance/internal-pdf-documents-are-given-a-structure-based-on-headings">Rule n° 234</a> - Internal PDF documents are given a structure based on titles.</blockquote>
<p>This one is a variant of the rule 227. The same benefits apply here as well. Use the formatting tools (Heading 1, Heading 2, etc.) in your software to generate a structured PDF.</p>
<h2 data-sanitized-id="conclusion-↑"><span data-sanitized-id="part5">Conclusion <a title="back to the summary" href="https://htmhell.dev/adventcalendar/2022/8/#s5">↑</a></span></h2>
<p>That's it! There are other rules. I invite you to dig more into these (writing about every rule would have made this article way too long). Remember: your approach towards SEO has to be "<em>user first</em>" (search engines will reward you for that). Think this way about SEO, but also for accessibility, performance, privacy, responsive design, eco-conception. Imagine all these themes cohabiting and interacting in a virtuous circle.</p>
<h3 data-sanitized-id="find-out-more">Find out more</h3>
<ul>
<li><a href="https://checklists.opquast.com/en/web-quality-assurance/">Opquast - The Web Quality Assurance Checklist</a></li>
<li><a href="https://developers.google.com/search/docs/fundamentals/get-started-developers">Google - Get started with Search: a developer's guide</a></li>
<li><a href="https://developers.google.com/search/docs/fundamentals/seo-starter-guide">Google - Search Engine Optimization (SEO) Starter Guide</a></li>
<li><a href="https://www.smashingmagazine.com/smashing-guide-search-engine-optimization/">Smashing Magazine - A Smashing Guide To The World Of Search Engine Optimization</a></li>
</ul>
<hr>
<h2 data-sanitized-id="footnotes"><span data-sanitized-id="footnote-label">Footnotes</span></h2>
<ol>
<li><span data-sanitized-id="ref1">Web Vitals is an initiative by Google to provide unified guidance for quality signals that are essential to delivering a great user experience on the web. See <a href="https://web.dev/vitals/">web.dev/vitals</a>. <a title="back to content" href="https://htmhell.dev/adventcalendar/2022/8/#sup1">↑</a></span></li>
<li><span data-sanitized-id="ref2">This definition is from the <em>Web Accessiblity Initiative</em>. More explanation at <a href="https://www.w3.org/WAI/fundamentals/accessibility-intro/#what">w3.org/WAI</a>. <a title="back to content" href="https://htmhell.dev/adventcalendar/2022/8/#sup2">↑</a> </span></li>
</ol>


guid: https://htmhell.dev/adventcalendar/2022/9/
title: You don't need HTML!
author: ;Manuel Matuzovic
link: https://htmhell.dev/adventcalendar/2022/9/
hash: ;��A�͏��Jy"d ��
attributes: {"enclosures":[]}
content:
<p>While browsing Mastodon late one night, I came across this excellent blog post called <a href="https://whitep4nth3r.com/blog/html-is-all-you-need-to-make-a-website/">HTML is all you need to make a website</a>. It describes a few websites which are pure HTML. No CSS and no JS.</p>
<p>And I thought… do you even need HTML to make a website?</p>
<p>A few hours later, I launched the <a href="https://no-ht.ml/">NO-HT.ML</a> website.  Proving, once and for all, that you <em>don't</em> need HTML to make a beautiful<sup data-sanitized-id="fnref-44154-ugly"><a href="https://htmhell.dev/adventcalendar/2022/9/#fn-44154-ugly" title="[You ain't got no alibi](https://youtu.be/I96LR5vqqqQ?t=15)." data-sanitized-class="">1</a></sup> responsive<sup data-sanitized-id="fnref-44154-resp"><a href="https://htmhell.dev/adventcalendar/2022/9/#fn-44154-resp" title="In that it generates a violent response from web designers." data-sanitized-class="">2</a></sup>, and useful<sup data-sanitized-id="fnref-44154-use"><a href="https://htmhell.dev/adventcalendar/2022/9/#fn-44154-use" title="I assume it will be used as part of my insanity defence." data-sanitized-class="">3</a></sup> website which everyone will love<sup data-sanitized-id="fnref-44154-hn"><a href="https://htmhell.dev/adventcalendar/2022/9/#fn-44154-hn" title="[For some value of everyone](https://news.ycombinator.com/item?id=33645398)." data-sanitized-class="">4</a></sup>.</p>
<p>
<img src="https://htmhell.dev/images/advent2022/9/banner.jpg" alt="you don't need HTML writing in ascii characters.">
</p>
<p>Go <a href="https://no-ht.ml/">take a look and marvel at its magnificence</a> - then come back here to discuss its profound importance.</p>
<h2 data-sanitized-id="how-it-works">How it works</h2>
<p>If you look at the source code, you'll see it uses a <em>tiny</em> scrap of (mostly) invalid markup to kick things off.</p>
<p><code>&lt;!doctype UNICODE&gt;</code> is a <em>fake</em> doctype. But it seems to be needed to convince some browsers into attempting to render the document.</p>
<p><code>&lt;meta charset="UTF-8"&gt;</code> is <em>real</em>. Without this, text encoding sniffing takes places and some browsers just displayed rubbish.</p>
<p><code>&lt;plaintext&gt;</code> is <em>also</em> a real HTML element. It was <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/plaintext">deprecated in HTML 2</a> back in the mid-1990s.  What's particularly interesting is that the element <em>cannot</em> be closed. If you manage to find a website which lets you post HTML, that can be particularly fun!</p>
<p>From there, the page starts with some ASCII art. There are loads of text generators around. I remember when it used to take hours to hand-draw things like that.</p>
<p>Next is a bunch of Unicode abuse. There are <em>loads</em> of "letter-like" shapes. They're included for compatibility with rendering mathematical and scientific documents.  There are also lots of punctuation marks - like bullets.</p>
<p>ASCII tables and flowcharts are pretty commonplace, although they sometimes go a bit wonky with non-fixed width characters.</p>
<p>And then, finally, the <a href="https://en.wikipedia.org/wiki/Arecibo_message">Arecibo message</a> using the <a href="https://unicodeplus.com/block/1F780">Geometric Shapes Extended Block</a>.</p>
<h2 data-sanitized-id="is-this-useful">Is this useful?</h2>
<p>I've been reading "Reality is Broken" a book all about game design. In it, I found this quote:</p>
<blockquote>Playing a game is the voluntary attempt to overcome unnecessary obstacles<sup data-sanitized-id="fnref-44154-cite"><a href="https://htmhell.dev/adventcalendar/2022/9/#fn-44154-cite" title="Suits, The Grasshopper" data-sanitized-class="">5</a></sup>.</blockquote>
<p>It can be <em>fun</em> to give yourself arbitrary restrictions.  In programming, there's a game called <a href="https://code.golf/">Code Golf</a> - where players compete to solve a coding challenge in the fewest number of characters.</p>
<p>That's what's going on here. People are playing a game - the rules of which are "Do normal thing X without using normal thing Y".</p>
<p>I encourage all of you to play games. Go use your imagination to build something in a ridiculously restricted way. What do the constraints do to the way you express yourself? What sense of satisfaction do you get from successfully creating something in an impossible manner? What will you learn from experimentation?</p>
<p>But, above all, have fun and show off your beautiful messes.</p>
<hr>
<div data-sanitized-class="footnotes">
	<ol>
		<li data-sanitized-id="fn-44154-ugly"><a href="https://youtu.be/I96LR5vqqqQ?t=15">You ain't got no alibi</a>. <a href="https://htmhell.dev/adventcalendar/2022/9/#fnref-44154-ugly" title="Return to main content.">↩</a></li>
		<li data-sanitized-id="fn-44154-resp">In that it generates a violent response from web designers. <a href="https://htmhell.dev/adventcalendar/2022/9/#fnref-44154-resp" title="Return to main content.">↩</a></li>
		<li data-sanitized-id="fn-44154-use">I assume it will be used as part of my insanity defence. <a href="https://htmhell.dev/adventcalendar/2022/9/#fnref-44154-use" title="Return to main content.">↩</a></li>
		<li data-sanitized-id="fn-44154-hn"><a href="https://news.ycombinator.com/item?id=33645398">For some value of everyone</a>. <a href="https://htmhell.dev/adventcalendar/2022/9/#fnref-44154-hn" title="Return to main content.">↩</a></li>
		<li data-sanitized-id="fn-44154-cite">Suits, The Grasshopper, 38. Katie Salen and Eric Zimmerman were among the first game researchers to outline these three characteristics as essential to a game, drawing on the work of Bernard Suits. Salen, Katie, and Eric Zimmerman. <a href="https://amzn.to/3VaFmxk">Rules of Play: Game Design Fundamentals</a> (Cambridge: MIT Press, 2004). <a href="https://htmhell.dev/adventcalendar/2022/9/#fnref-44154-cite" title="Return to main content.">↩</a></li>
	</ol>
</div>


guid: https://htmhell.dev/adventcalendar/2022/10/
title: Dear developer, your assumptions are wrong
author: ;Manuel Matuzovic
link: https://htmhell.dev/adventcalendar/2022/10/
hash: &,D��p��� W5 �l;
attributes: {"enclosures":[]}
content:
<p>As developers, validation of user input is one of the first things we are taught.<br>
What we usually learn a lot later (or sometimes never), is to challenge our own biases and assumptions.</p>
<p>So, for example, we may think it would be a good idea to put some restrictions in an input field for a name:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>name<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>First name:<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>text<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">minlength</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>3<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">maxlength</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>20<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>name<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>You might be surprised at discovering how many people in the world have names with just 1 or 2 letters (Read the article <a href="https://brucelawson.co.uk/2022/inclusive-name-inputs-because-not-everyone-is-called-chad-pancreas/">Inclusive name inputs – because not everyone is called Chad Pancreas </a> by Bruce Lawson for examples), or maybe you can try to fit the full name of <a href="https://www.britannica.com/question/What-is-Picassos-full-name">Pablo Diego José Francisco de Paula Juan Nepomuceno Crispín Crispiniano María de los Remedios de la Santísima Trinidad Ruiz Picasso</a> in your poor name field.<br>
Additionally, in many cultures of the world, no such thing as first name and last name separation exists, some people don't have any last name, and other similar cases.</p>
<p>But if you absolutely want to add some kind of validation, you can try with a <code>pattern</code> attribute:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>name<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>First name:<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>text<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">pattern</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>[a-zA-Z]{2,20}<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>name<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>So... you're assuming names can only contain <em>A-Z</em> letters. What do we say then to Lee-Ann, Niccolò, Noëmi, and Mohammed-Ibrahim? We say <a href="https://twitter.com/yournameisvalid">“your name is invalid!”</a>, of course.<br>
At least, let's try to be more kind in the error messages.</p>
<p><img src="https://pbs.twimg.com/media/FdV8wTpWQAEIIcG?format=png&amp;name=small" alt='a screenshot showing error message saying: "please enter a valid name"'></p>
<p>It's also not very nice when your phone auto-corrects your name with a wrong value. You could consider adding an <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete">autocomplete attribute</a> to the field, such as:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>name<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>First name:<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">autocomplete</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>name<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">autocorrect</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>off<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">spellcheck</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>false<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>name<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token punctuation">/&gt;</span></span></span></code></pre>
<p>There are a lot of things that we are not aware of, and thinking about all the possible edge cases and unusual scenarios can be really challenging. We should try to test with real users as much as possible or at least do some research on who they are / who they could be.</p>
<p>You can find more information about this validation problem on the <a href="https://www.w3.org/International/questions/qa-personal-names">W3C website</a>, together with possible solutions and suggested best practices.</p>
<p>Check out <a href="https://github.com/kdeldycke/awesome-falsehood">awesome-falsehood</a> to see more examples of wrong assumptions about names, phone numbers, addresses and so on.</p>


guid: https://htmhell.dev/adventcalendar/2022/11/
title: There can be only one: Options for building “choose one” fields
author: ;Manuel Matuzovic
link: https://htmhell.dev/adventcalendar/2022/11/
hash: �F9ȴN*���/ ���
attributes: {"enclosures":[]}
content:
<p>When it comes to building out forms, it sometimes seems like there are at once both too few field types and too many. This is especially true when it comes to having users choose an option from a pre-defined list, also known as “choose one” fields.</p>
<p>This article will take you on a three-stop tour of the most common ways to enable this kind of response in your forms, using just HTML. I’ll talk about some of the implications for CSS and JavaScript as well, but this is HTMHell after all, so my main focus is on the markup.</p>
<h2 data-sanitized-id="selection-controls-(aka-drop-downs)">Selection controls (a.k.a., drop-downs)</h2>
<p>The <code>&lt;select&gt;</code> dropdown has been a mainstay of web forms since they first debuted in HTML 2. This relatively simple element allows for an author to define multiple choices for the user to choose from and the whole thing is neatly packaged in a compact control that can be manipulated via the mouse or keyboard or both.</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>What’s your favorite fruit?<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>select</span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Apple<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Orange<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>select</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="demo">
<label for="fruit">What’s your favorite fruit?</label><br>
<select name="fruit" data-sanitized-id="fruit">
<option>Apple</option>
<option>Orange</option>
</select>
</p>
<p>By default, the text value of the chosen <code>&lt;option&gt;</code> is the value of the field. Authors can override this behavior by setting a <code>value</code> on the <code>&lt;option&gt;</code> too:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>location<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Where are you based?<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>select</span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>location<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>location<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>US<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>United States<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>non-US<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Outside the United States<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>select</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="demo">
<label for="location">Where are you based?</label><br>
<select name="location" data-sanitized-id="location">
  <option value="US">United States</option>
  <option value="non-US">Outside the United States</option>
</select>
</p>
<p>By default, the first <code>&lt;option&gt;</code> in the list is used as the default value for the field, which is why you often see <code>&lt;select&gt;</code> elements begin with an empty value:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>What’s your favorite fruit?<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>select</span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span><span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>-- Choose One --<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Apple<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Orange<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>select</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="demo">
<label for="fruit2">What’s your favorite fruit?</label><br>
<select name="fruit" data-sanitized-id="fruit2">
  <option value="">-- Choose One --</option>
  <option>Apple</option>
  <option>Orange</option>
</select>
</p>
<p>Authors can specify a default value by setting the <code>selected</code> attribute on the appropriate <code>&lt;option&gt;</code>:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>What’s your favorite fruit?<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>select</span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span><span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>-- Choose One --<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Apple<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span> <span data-sanitized-class="token attr-name">selected</span><span data-sanitized-class="token punctuation">&gt;</span></span>Orange<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>select</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="demo">
<label for="fruit3">What’s your favorite fruit?</label><br>
<select name="fruit" data-sanitized-id="fruit3">
  <option value="">-- Choose One --</option>
  <option>Apple</option>
  <option selected>Orange</option>
</select>
</p>
<p><em>Note: If multiple <code>&lt;option&gt;</code> elements in the same <code>&lt;select&gt;</code> have a <code>selected</code> attribute applied to them, the last one in the source order wins.</em></p>
<p>Though it’s seldom used, <code>&lt;select&gt;</code> fields also support grouping options using <code>optgroup</code>:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>What’s your favorite fruit?<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>select</span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>optgroup</span> <span data-sanitized-class="token attr-name">label</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Pome<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Apple<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Pear<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>optgroup</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>optgroup</span> <span data-sanitized-class="token attr-name">label</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Citrus<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Orange<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Tangerine<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span> </span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>optgroup</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>select</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="demo">
<label for="fruit4">What’s your favorite fruit?</label><br>
<select name="fruit" data-sanitized-id="fruit4">
  <optgroup label="Pome">
    <option>Apple</option>
    <option>Pear</option>
  </optgroup>
  <optgroup label="Citrus">
    <option>Orange</option>
    <option>Tangerine</option> 
  </optgroup>
</select>
</p>
<p>Another benefit of <code>&lt;select&gt;</code> is that it’s easy to validate on the client side. All you need to do is slap a <code>required</code> attribute on there and modern browsers will ensure a value is chosen before the form can be submitted. Don’t forget to use <code>aria-required="true"</code> to ensure that requirement is exposed to assistive technology as well.</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>What’s your favorite fruit?<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>select</span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span><br>  <span data-sanitized-class="token attr-name">required</span> <span data-sanitized-class="token attr-name">aria-required</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>true<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span><span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>-- Choose One --<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Apple<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span> <span data-sanitized-class="token attr-name">selected</span><span data-sanitized-class="token punctuation">&gt;</span></span>Orange<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>select</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="demo">
<label for="fruit5">What’s your favorite fruit?</label><br>
<select name="fruit" required="" aria-required="true" data-sanitized-id="fruit5">
  <option value="">-- Choose One --</option>
  <option>Apple</option>
  <option selected>Orange</option>
</select>
</p>
<p>One of the major benefits of <code>&lt;select&gt;</code> is that it’s an extremely compact component, only displaying one choice at a time (provided you aren’t using the <code>multiple</code> variety that allows multi-selection). This can preserve a lot of screen real estate. That minimal footprint comes at a price, however, as it requires users to interact with the field to see all of the choices. Additionally, extremely long lists of choices will require users scroll the dropdown to see everything.</p>
<p>To speed up navigation in the list of choices, <code>&lt;select&gt;</code> elements do support keyboard-based movement. Users can use <kbd>up</kbd> and <kbd>down</kbd> to move around in the list. They can also jump around in the list by typing (a.k.a., "type ahead"). For example, if a user were filling out the field above and typed "o," the value would become "orange." If they opened the drop-down before typing, focus would move to "orange" but the value would not be set unless "orange" was chosen (using <kbd>enter</kbd> or <kbd>space</kbd>).</p>
<p>It’s worth noting that the matching algorithm for "type ahead" is limited. First, the string match needs to be with the start of the <code>&lt;option&gt;</code>’s display text. Second, <em>only</em> the display text is considered, meaning it will not match the <code>value</code> if it differs from what is shown to users.</p>
<p>Another limitation of the <code>&lt;select&gt;</code> is its style-ability (or lack thereof). In the past this was a <em>really</em> big deal because browsers rendered <code>&lt;select&gt;</code> drop-downs wildly differently and many of them were highly stylized to match the host OS.</p>
<table>
  <caption>A selection of <code>&lt;select&gt;</code> styles across Windows XP and OS X, circa 2007</caption>
  <thead>
    <tr>
      <th scope="col">OS</th>
      <th scope="col">Browser</th>
      <th scope="col"><code>select</code></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td rowspan="5">Windows XP</td>
      <td>Firefox</td>
      <td>
        <img alt="Screenshot of a select in Firefox for Windows XP, showing the grey chunky old school drop-down" src="https://htmhell.dev/images/advent2022/10/select-xp-firefox.png">
      </td>
    </tr>
    <tr>
      <td>IE 6/7 (XP)</td>
      <td>
      <img alt="Screenshot of a select in IE6 &amp; IE7 for Windows XP in XP mode, showing the colorful, XP-themed drop-down" src="https://htmhell.dev/images/advent2022/10/select-xp-ie.png">
      </td>
    </tr>
    <tr>
      <td>IE 6 (classic)</td>
      <td>
        <img alt="Screenshot of a select in IE6 for Windows XP in “classic” mode, showing the grey chunky old school drop-down" src="https://htmhell.dev/images/advent2022/10/select-xp-ie6-classic.png">
      </td>
    </tr>
<tr>
<td>IE 7 (classic)</td>
<td>
<img alt="Screenshot of a select in IE7 for Windows XP in classic mode, showing the grey chunky old school drop-down" src="https://htmhell.dev/images/advent2022/10/select-xp-ie7-classic.png">
</td>
</tr>
<tr>
<td>Opera</td>
<td>
<img alt="Screenshot of a select in Opera for Windows XP, showing the grey chunky old school drop-down" src="https://htmhell.dev/images/advent2022/10/select-xp-ie7-classic.png">
</td>
</tr>
<tr>
<td rowspan="5">OS X</td>
<td>Camino</td>
<td>
<img alt="Screenshot of a select in Camino for OS X, showing the 3D-stylized “Aqua” theme drop-down" src="https://htmhell.dev/images/advent2022/10/select-osx-camino.png">
</td>
</tr>
<tr>
<td>Firefox</td>
<td>
<img alt="Screenshot of a select in Firefox for OS X, showing the grey chunky old school drop-down" src="https://htmhell.dev/images/advent2022/10/select-osx-firefox.png">
</td>
</tr>
<tr>
<td>IE 5</td>
<td>
<img alt="Screenshot of a select in IE5 for OS X, showing a muted grey toggle with up and down arrows (a wholly unique design)" src="https://htmhell.dev/images/advent2022/10/select-osx-ie5.png">
</td>
</tr>
<tr>
<td>Opera</td>
<td>
<img alt="Screenshot of a select in Opera for OS X, showing the 3D-stylized “Aqua” theme drop-down" src="https://htmhell.dev/images/advent2022/10/select-osx-opera.png">
</td>
</tr>
<tr>
<td>Safari</td>
<td>
<img alt="Screenshot of a select in Safari for OS X, showing the 3D-stylized “Aqua” theme drop-down" src="https://htmhell.dev/images/advent2022/10/select-osx-safari.png">
</td>
</tr>
</tbody>
</table>
<p>It’s unsurprising that dozens upon dozens of <code>&lt;select&gt;</code> replacements arose during this period, most of which were highly inaccessible. I worked on one for ages—and <a href="https://www.google.com/books/edition/AdvancED_DOM_Scripting/Wmg6dkBJd50C?hl=en&amp;gbpv=1&amp;pg=PA507&amp;printsec=frontcover">wrote a lengthy book chapter about the experience</a>. In the end, I managed to replicate most of the core functionality of a true <code>&lt;select&gt;</code> (including <code>optgroup</code> support, keyboard accessibility and more… all progressively enhanced) but it required a lot of extra code and was incredibly fragile (as most client-side JavaScript-dependent interfaces are). I never ended up deploying my <code>&lt;select&gt;</code> replacement because the extra download cost just didn’t seem worthwhile just to get a drop-down that looked the way I wanted it to.</p>
<p>Thankfully, browsers have largely toned down the design of their <code>&lt;select&gt;</code> drop-downs, making them blend more seamlessly into our websites. We’ve also been granted a bit more control when it comes to styling <code>&lt;select&gt;</code> elements, especially when we apply <code>appearance: none</code>.</p>
<p>The <code>appearance</code> property governs how an element is rendered. In the case of <code>&lt;select&gt;</code>, setting it to "none" removes the default UI bits that makes a <code>&lt;select&gt;</code> look like a <code>&lt;select&gt;</code>. If you go this route, you have a lot more control over the look and feel of the element, but you also need to add in UI affordances like the arrow indicator, which typically requires you to inject additional markup. Depending on how important it is for you to control the look of a <code>&lt;select&gt;</code>, you may find it worth doing. I generally don’t.</p>
<p>It’s worth noting that the Open UI team is actively working on <a href="https://open-ui.org/prototypes/selectmenu">a successor to <code>&lt;select&gt;</code> called <code>selectmenu</code></a>. It works largely the same as a <code>&lt;select&gt;</code>, but it’s highly configurable. Its design can also be fully controlled via CSS. The <code>selectmenu</code> component is currently available as an experimental feature in Chromium-based browsers.</p>
<p>Though it’s a bit of an edge case, the final challenge presented by the <code>&lt;select&gt;</code> elements is support for a user-defined value. While not impossible to achieve, it is a little more verbose, from a markup standpoint:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>What’s your favorite fruit?<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>select</span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Apple<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Orange<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Other<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>select</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit-other<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>If you chose "other," what <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>em</span><span data-sanitized-class="token punctuation">&gt;</span></span>is<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>em</span><span data-sanitized-class="token punctuation">&gt;</span></span> your favorite fruit?<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit-other<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="demo">
<label for="fruit6">What’s your favorite fruit?</label><br>
<select name="fruit" data-sanitized-id="fruit6">
  <option>Apple</option>
  <option>Orange</option>
  <option>Other</option>
</select><br>
<label for="fruit-other">If you chose "other," what <em>is</em> your favorite fruit?</label><br>

</p>
<p>Using the above markup, you need to ensure your form processing logic overrides the initial "fruit" value with the user-supplied one. Most back-end languages do this automatically, but if you’re processing the data on the client side it’s something to be aware of. Alternately, you could give the text <code>&lt;input&gt;</code> a unique <code>name</code> (e.g., "fruit_other") and check for "fruit" to equal "Other" before replacing that value with the "fruit_other" value.</p>
<p>Client-side validation of this construct is also a bit more involved. It requires that you use JavaScript to dynamically update the "other" field’s <code>required</code> (and <code>aria-required</code>) status, based the user choice from the <code>&lt;select&gt;</code> dropdown.</p>
<p>There is a whole lot more we could explore when it comes to <code>&lt;select&gt;</code>, but this is a good introduction to the mechanics of the element.</p>
<table>
<caption>Summary: <code>&lt;select&gt;</code></caption>
<thead><tr>
<th scope="col">Pros</th>
<th scope="col">Cons</th>
</tr></thead>
<tbody><tr>
<td>
<ul>
<li>compact</li>
<li>value and display text can differ</li>
<li>supports value grouping</li>
</ul>
</td>
<td>
<ul>
<li>options are hidden</li>
<li>UI varies</li>
<li>CSS styling is limited</li>
<li>user-supplied values are challenging</li>
</ul>
</td>
</tr></tbody>
</table>
<h2 data-sanitized-id="radio-controls">Radio controls</h2>
<p>As with <code>&lt;select&gt;</code>, radio controls (<code>input[type=radio]</code>) have been a part of HTML forms since they debuted. In order to be accessible, radio controls require a bit more markup as each <code>&lt;input&gt;</code> requires a <code>&lt;label&gt;</code>. Here is a minimalist example:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>fieldset</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>legend</span><span data-sanitized-class="token punctuation">&gt;</span></span>What’s your favorite fruit?<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>legend</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>radio<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Apple<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    Apple</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>radio<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Orange<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    Orange</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>fieldset</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<div data-demo="demo">
<fieldset>
  <legend>What’s your favorite fruit?</legend>
  <label>
    
    Apple
  </label>
  <label>
    
    Orange
  </label>
</fieldset>
</div>
<p>Here’s what’s going on in this code block:</p>
<ul>
<li>The <code>fieldset</code> is binding the whole construct together as a group</li>
<li>The <code>legend</code> provides the group’s label.</li>
<li>Each radio control (<code>input[type=radio]</code>) is ensconced in a <code>&lt;label&gt;</code> to ensure it reads properly for accessibility.</li>
</ul>
<p>I also generally like to wrap the choices within a list (typically a <code>ul</code>, unless the order matters) because I like how it looks when styles aren’t applied. You could also opt for a <code>div</code> or <code>p</code> or nothing at all (as I did in the above example). If you don’t use a wrapper, just make sure your <code>&lt;label&gt;</code> elements are set to <code>display: block</code> so the choices don’t run into one another.</p>
<p>You might be wondering why I chose to wrap the <code>&lt;label&gt;</code> elements around the radio <code>&lt;input&gt;</code> controls. This is something I’ve done for a long time because it creates an implicit <code>&lt;label&gt;</code> association with the <code>&lt;input&gt;</code>.<sup><a href="https://htmhell.dev/adventcalendar/2022/11/#note1">1</a></sup> It also allows me to write a really succinct selector to differentiate <code>&lt;label&gt;</code> elements used with radio controls (and checkboxes), which wrap the <code>&lt;input&gt;</code>, from those used for labeling other <code>&lt;input&gt;</code> types, <code>&lt;select&gt;</code>, and <code>textarea</code>, which don’t wrap the field.</p>
<p><sup data-sanitized-id="note1">1</sup>: If you still have users on <em>really</em> old browsers (think IE7), you should double up with explicit association (using the <code>for</code> attribute as an <code>id</code> reference to the <code>&lt;input&gt;</code>) too as those older browsers require it.</p>
<pre data-sanitized-class="language-css"><code data-sanitized-class="language-css"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token selector">label</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">font-weight</span><span data-sanitized-class="token punctuation">:</span> bold<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">display</span><span data-sanitized-class="token punctuation">:</span> block<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token punctuation">}</span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token selector">label:has(input)</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">font-weight</span><span data-sanitized-class="token punctuation">:</span> normal<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token punctuation">}</span></span></code></pre>
<p>When folks talk about using <code>&lt;label&gt;</code>, they frequently focus on how crucial they are for the accessibility of your forms. That’s absolutely true and you need them for that. What isn’t often discussed is that <code>&lt;label&gt;</code> elements have a hidden superpower: When you click or tap a <code>&lt;label&gt;</code> associated with a radio control, the <code>&lt;input&gt;</code> will be selected.<sup><a href="https://htmhell.dev/adventcalendar/2022/11/#note1">1</a></sup> That means using a paper label actually increases the hit target for the <code>&lt;input&gt;</code>, which is a usability win! In fact, proper labeling makes the age-old complaint—that radio controls don’t have large enough hit targets to be mobile friendly—entirely moot.</p>
<p><sup data-sanitized-id="note2">2</sup>: When you click a <code>&lt;label&gt;</code> associated with another field type (e.g., <code>&lt;select&gt;</code>, <code>input[type=text]</code>), the field will receive focus. When you click a <code>&lt;label&gt;</code> associated with a checkbox <code>&lt;input&gt;</code>, it will toggle selection of the <code>&lt;input&gt;</code>.</p>
<p>Radio controls are perfect for when you want users to be able to more easily scan the available choices. Given that every choice is on display, however, they become less useful the more choices on offer. As a general rule, UX folks suggest <a href="https://www.justinmind.com/ui-design/radio-button-patterns-examples#:~:text=Some%20designers%2C%20like%20folks%20over%20at%20UX%20Movement%2C,space%2C%20while%20not%20asking%20too%20much%20from%20users">limiting radio controls to no more than 5 choices</a>, but there are exceptions to every rule. The most important thing to consider is whether users need to be able to read and evaluate the choices against one another. You should also do everything you can to <a href="https://www.aaron-gustafson.com/notebook/consider-how-your-forms-read/">ensure the choices are clear, concise, and make sense to your intended audience</a>.</p>
<p>Another benefit to using radio controls is that the <code>&lt;label&gt;</code> can be more than just text. There are limits, however. Since a <code>&lt;label&gt;</code> is interactive (see above), you can’t nest other interactive elements (e.g., <code>a</code>, <code>button</code>, <code>audio</code>, <code>video</code>) within one. It’s also recommended that you avoid putting headings (<code>h1</code>–<code>h6</code>) inside a label as it can cause navigational issues for users of assistive technologies. You can, however, include other non-interactive <a href="https://developer.mozilla.org/docs/Web/Guide/HTML/Content_categories#phrasing_content">phrasing elements</a>, including images. That also means you can style the contents of a radio control <code>&lt;label&gt;</code> pretty much any way you like, provided its functionality is still obvious.</p>
<p>To establish a default <code>value</code> for the radio group, apply a <code>checked</code> attribute to the associated <code>&lt;input&gt;</code>. As with <code>&lt;option&gt;</code> lists, the last radio <code>&lt;input&gt;</code> in the group that’s <code>checked</code> will be the default value of the field.</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>fieldset</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>legend</span><span data-sanitized-class="token punctuation">&gt;</span></span>What’s your favorite fruit?<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>legend</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>radio<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Apple<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    Apple</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br>    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>radio<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Orange<span data-sanitized-class="token punctuation">"</span></span> <br>           <span data-sanitized-class="token attr-name">checked</span><span data-sanitized-class="token punctuation">&gt;</span></span><br><span data-sanitized-class="highlight-line">    Orange</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>fieldset</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<div data-demo="demo">
<fieldset>
  <legend>What’s your favorite fruit?</legend>
  <label>
    
    Apple
  </label>
  <label>
    
    Orange
  </label>
</fieldset>
</div>
<p>Radio controls can be designated as required too, using the same <code>required</code> attribute you’d use in a <code>&lt;select&gt;</code>. You only need to add the attribute to one of the radio controls in the group to prevent the form from being submitted until the user has chosen one of the options. If you are working on a form where the choices change often, you might consider adding the <code>required</code> attribute to each of the <code>&lt;input&gt;</code> elements in order to ensure it doesn’t disappear if the one <code>&lt;input&gt;</code> in the group with that attribute gets removed for some reason. There’s no penalty for having the attribute repeated on every <code>&lt;input&gt;</code> in the group.</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>fieldset</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>legend</span><span data-sanitized-class="token punctuation">&gt;</span></span>What’s your favorite fruit?<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>legend</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br>    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>radio<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Apple<span data-sanitized-class="token punctuation">"</span></span><br>           <span data-sanitized-class="token attr-name">required</span><span data-sanitized-class="token punctuation">&gt;</span></span><br><span data-sanitized-class="highlight-line">    Apple</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br>    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>radio<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Orange<span data-sanitized-class="token punctuation">"</span></span><br>           <span data-sanitized-class="token attr-name">required</span><span data-sanitized-class="token punctuation">&gt;</span></span><br><span data-sanitized-class="highlight-line">    Orange</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>fieldset</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<div data-demo="demo">
<fieldset>
  <legend>What’s your favorite fruit?</legend>
  <label>
    
    Apple
  </label>
  <label>
    
    Orange
  </label>
</fieldset>
</div>
<p>As with <code>&lt;select&gt;</code>, supporting user-defined values requires a bit more complexity:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>fieldset</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>legend</span><span data-sanitized-class="token punctuation">&gt;</span></span>What’s your favorite fruit?<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>legend</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>radio<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Apple<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    Apple</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>radio<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Orange<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    Orange</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>radio<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>Other<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    Other</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit-other<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>If you chose "other," what <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>em</span><span data-sanitized-class="token punctuation">&gt;</span></span>is<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>em</span><span data-sanitized-class="token punctuation">&gt;</span></span> your favorite fruit?<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit-other<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>p</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>fieldset</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<div data-demo="demo">
<fieldset>
  <legend>What’s your favorite fruit?</legend>
  <label>
    
    Apple
  </label>
  <label>
    
    Orange
  </label>
  <label>
    
    Other
  </label>
  <br>
  <p>
    <label for="fruit-other">If you chose "other," what <em>is</em> your favorite fruit?</label>
    
  </p>
</fieldset>
</div>
<p>All of the same considerations outlined in my discussion of this approach for <code>&lt;select&gt;</code> apply to user-supplied values in the context of radio controls as well. The JavaScript necessary to toggle <code>required</code> and <code>aria-required</code> on the text <code>&lt;input&gt;</code>, however, may be a little more complicated, depending on how you set up your event listeners.</p>
<p>While a little more complicated to author, radio controls remain a solid choice when creating a "choose one" type field.</p>
<table>
<caption>Summary: <code>input[type=radio]</code></caption>
<thead><tr>
<th scope="col">Pros</th>
<th scope="col">Cons</th>
</tr></thead>
<tbody><tr>
<td>
<ul>
<li>all choices are visible</li>
<li>choices can be more than just text</li>
</ul>
</td>
<td>
<ul>
<li>markup is more complicated</li>
<li>too many choices can be problematic</li>
<li>user-supplied values are challenging</li>
</ul>
</td>
</tr></tbody>
</table>
<h2 data-sanitized-id="suggested-values">Suggested values</h2>
<p>The final option for "choose one" type fields is binding an <code>&lt;input&gt;</code> to a <code>&lt;datalist&gt;</code>. This option debuted as part of HTML5. The user experience is quite similar to the experience you get typing in your browser’s address bar: As you type, the UI suggests values for you, based on what you’re typing.</p>
<p><img src="https://htmhell.dev/images/advent2022/10/datalist.gif" alt="Interacting with a datalist-backed input in Chrome Canary for macOS. When typing, suggestions are provided and users can pick one using the keyboard or mouse."></p>
<p>The markup for this construct is pretty straightforward:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>label</span> <span data-sanitized-class="token attr-name">for</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>What’s your favorite fruit?<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>label</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">name</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">list</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit-options<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>datalist</span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>fruit-options<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Apple<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span>Orange<span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>option</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>datalist</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p data-sanitized-class="demo">
<label for="fruit">What’s your favorite fruit?</label><br>

<datalist data-sanitized-id="fruit-options">
  <option>Apple</option>
  <option>Orange</option>
</datalist>
</p>
<p>First, you create a <code>&lt;datalist&gt;</code> element, assign it an <code>id</code>, and fill it with <code>&lt;option&gt;</code> elements for the choices (making it look a lot like a <code>&lt;select&gt;</code>). Then you add a <code>list</code> attribute to the associated <code>&lt;input&gt;</code> and set its value to the <code>id</code> of the <code>&lt;datalist&gt;</code>. It’s worth noting that you can also reference a single <code>&lt;datalist&gt;</code> from multiple <code>&lt;input&gt;</code> fields, should you need to.</p>
<p><em>Note: Unlike in a <code>&lt;select&gt;</code>, the <code>selected</code> attribute does nothing when set on an <code>&lt;option&gt;</code> in a <code>&lt;datalist&gt;</code>. Use the <code>value</code> attribute on the <code>&lt;input&gt;</code> to provide a default value.</em></p>
<p>As with the <code>&lt;select&gt;</code>, <code>input[list]</code> is a very compact choice because it’s just a single <code>&lt;input&gt;</code> field. Also like <code>&lt;select&gt;</code>, however, this approach doesn’t make a user’s potential choices very obvious. In fact, you could argue it makes them even less obvious than a <code>&lt;select&gt;</code> does, on account of the predictive typing behavior. That said, it does borrow some UX goodies from <code>&lt;select&gt;</code> in that users can make a choice from the "picker" UI using their keyboard or mouse. They also have the option to just type out their response.</p>
<p>That’s one of the real strengths of <code>&lt;datalist&gt;</code>: It naturally supports user-defined values over and above the <code>&lt;datalist&gt;</code> suggestions. That’s a double-edged sword, of course, in that there’s no way to force a user to pick only from the choices you provide. You need to use a <code>&lt;select&gt;</code> if that’s a requirement.</p>
<p>Requiring a <code>&lt;datalist&gt;</code> field is just as straightforward as it is with the other field types. Add the <code>required</code> attribute (and <code>aria-required</code>) to the <code>&lt;input&gt;</code> and you’re good to go.</p>
<p>As I mentioned, <code>&lt;datalist&gt;</code> became a part of HTML much more recently than the other two options. Older browsers have no idea what to do when they encounter <code>&lt;datalist&gt;</code>, so they will ignore it. That’s totally cool because you still end up with a usable text <code>&lt;input&gt;</code>. Perfect progressive enhancement!</p>
<p>The <code>&lt;datalist&gt;</code> approach is hands-down the best choice if you want to suggest potential responses, but also want to give users the option of providing a different value if they need to.</p>
<table>
<caption>Summary: <code>&lt;datalist&gt;</code></caption>
<thead><tr>
<th scope="col">Pros</th>
<th scope="col">Cons</th>
</tr></thead>
<tbody><tr>
<td>
<ul>
<li>compact</li>
<li>user-supplied values are easy</li>
<li>degrades to a standard <code>&lt;input&gt;</code></li>
<li>can fall back to <code>&lt;input&gt;</code></li>
</ul>
</td>
<td>
<ul>
<li>options are hidden</li>
<li>UI varies</li>
<li>not obvious that users can pick from pre-defined values</li>
<li>users doesn’t need to choose a pre-defined value</li>
</ul>
</td>
</tr></tbody>
</table>
<h2 data-sanitized-id="make-your-choice">Make your choice</h2>
<p>Having seen these varying options, which one should you use? As with many things on the web, it depends on the context. If the choice is between a handful of items, a set of radio controls is likely the best option. You’d also want radio controls if the choices need to include something besides text. If the number of choices is substantial, a <code>&lt;select&gt;</code> or <code>&lt;datalist&gt;</code> might be the way to go. And if you need to keep things flexible, <code>&lt;datalist&gt;</code> is likely your best bet.</p>
<p>While it may be frustrating to have to evaluate so many options, it’s also good to have the flexibility these different approaches enable.</p>
<hr>
<p><em>I used CodePen to assemble <a href="https://codepen.io/aarongustafson/pen/ExRXzMz">a minimally-styled demo of all of the fields discussed in this article</a>, if you’d like to experiment with them yourself.</em></p>


guid: https://odysee.com/tcf-speaker-series-ep1-eva-bartlett:04e7e175a2e0bdec1a65c90a8142fda076df038b
author: ;Eva K Bartlett
link: https://odysee.com/tcf-speaker-series-ep1-eva-bartlett:04e7e175a2e0bdec1a65c90a8142fda076df038b
hash: 5�O�6J�H:�J�� �
title:
"TCF Speaker Series Ep1: Eva Bartlett: Donbass’ Pain &amp; Resolve, Shadows of Syria, Canadian Betrayal"

content:
<p><img src="https://thumbnails.lbry.com/x4kZjl1Y-TE" width="480" alt="thumbnail" title="" tcf speaker series ep1: eva bartlett: donbass pain resolve shadows of syria canadian betrayal></p>I was recently interviewed by Aiden Jonah of The Canada Files.<br>https://www.youtube.com/watch?v=qYqXdiY4LFU<br><br>TCF launches end-of-year fundraising campaign!<br>https://www.youtube.com/watch?v=0mAYbF3RZ9Y<br><br>Related links at this blog post:<br>https://ingaza.wordpress.com/2022/12/11/interview-tcf-speaker-series-ep1-eva-bartlett-donbass-pain-resolve-shadows-of-syria-canadian-betrayal/<br><br>*Please consider following me on other platforms. My time here on Youtube is limited &amp; will end.  I'm on:<br>https://odysee.com/@EvaKareneBartlett:9<br>https://rumble.com/c/c-2030196<br>https://t.me/Reality_Theories<br>*<br>...<br>https://www.youtube.com/watch?v=x4kZjl1Y-TE

attributes:
{"enclosures":[{"url":"https://player.odycdn.com/api/v3/streams/free/tcf-speaker-series-ep1-eva-bartlett/04e7e175a2e0bdec1a65c90a8142fda076df038b/403472.mp4","type":"video/mp4","length":248655460}]}


guid: https://htmhell.dev/adventcalendar/2022/12/
title: DOM Clobbering
author: ;Manuel Matuzovic
link: https://htmhell.dev/adventcalendar/2022/12/
hash: 6W�� ���֚ԇ}l�
attributes: {"enclosures":[]}
content:
<h3 data-sanitized-id="motivation">Motivation</h3>
<p>When thinking of HTML-related security bugs, people often think of script injection attacks, which is also known as <a href="https://en.wikipedia.org/wiki/Cross-site_scripting">Cross-Site Scripting</a> (XSS). If an attacker is able to submit, modify or store content on your web page, they might include evil JavaScript code to modify the page or steal user information like cookies.<br>
Most developers out there protect their websites against XSS by disallowing or controlling script execution.</p>
<p>However, this article is <strong>NOT</strong> about XSS.</p>
<p>This article is about an interesting attack that relies on HTML-only injections. The techniques here were <a href="http://www.thespanner.co.uk/2013/05/16/dom-clobbering/">first described by Gareth Heyes in 2013</a>, the topic gained additional attention due to a <a href="https://publications.cispa.saarland/3756/">recent research paper</a> and its accompanying website <a href="https://domclob.xyz/">https://domclob.xyz/</a> from Khodayari et al.</p>
<h3 data-sanitized-id="background">Background</h3>
<p>Before we dive into the vulnerability class of DOM Clobbering, we need to establish some background.</p>
<p>Have you ever noticed that whenever you include a HTML element with an <code>id</code> attribute, it becomes available as a global name (and a name on the <code>window</code> object)? So, for example</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>form</span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span>freddy</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>…will lead to <code>window.freddy</code> becoming a reference to that form element.</p>
<p>This is a legacy inheritance from the very old days of HTML and also known as <em><a href="https://html.spec.whatwg.org/multipage/nav-history-apis.html#named-access-on-the-window-object">named property access</a></em> in the HTML spec. Studying the spec will inform us that the following elements will also appear on the <code>document</code> object: <code>embed</code>, <code>form</code>, <code>img</code>, and <code>object</code>.</p>
<p>Given that web browsers have to maintain backwards compatibility support for relatively old web pages, <em>named property access</em> is designed in such a way <a href="https://webidl.spec.whatwg.org/#legacy-platform-object-abstract-ops">that element references come before lookups of APIs</a> and other new attributes on the <code>window</code> and <code>document</code> object.</p>
<h3 data-sanitized-id="dom-clobbering-attacks">DOM Clobbering Attacks</h3>
<p>In essence, this means that an attacker with the ability to inject HTML may mess with simple Web APIs - like the property <code>document.hidden</code>:</p>
<p>Imagine your website is trying to reduce or stop animations based on page visibility like so:</p>
<pre data-sanitized-class="language-js"><code data-sanitized-class="language-js"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token keyword">if</span> <span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token operator">!</span>document<span data-sanitized-class="token punctuation">.</span>hidden<span data-sanitized-class="token punctuation">)</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token function">startAnimations</span><span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token punctuation">)</span><span data-sanitized-class="token punctuation">;</span> </span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token punctuation">}</span></span></code></pre>
<p>an injected HTML form element will be able to make this truthy, regardless of whether the page is really hidden:</p>
<p>With <code>&lt;form id=hidden&gt;</code> the value <code>document.hidden</code> would return a <code>HTMLFormElement</code> and therefore be considered truthy.</p>
<p>So, in essence, DOM Clobbering is an attack where injected HTML may confuse the existing JavaScript application and therefore change the application logic.</p>
<p>Another typical example of this vulnerability is where code is trying to fall back to a default config if some variable is set, like so:</p>
<pre data-sanitized-class="language-js"><code data-sanitized-class="language-js"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token keyword">let</span> config <span data-sanitized-class="token operator">=</span> defaultConfig <span data-sanitized-class="token operator">||</span> <span data-sanitized-class="token punctuation">{</span> <span data-sanitized-class="token comment">/* some config here */</span><span data-sanitized-class="token punctuation">}</span><span data-sanitized-class="token punctuation">;</span></span></code></pre>
<p>If the <code>defaultConfig</code> name is clobbered, that other config is never going to be assigned correctly!</p>
<p>Let's look at a third, more complicated example: In this case, an attacker has injected two input elements with a <code>id</code> attribute of <code>childNodes</code> into an existing form <code>f</code> like here:</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>form</span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span>f</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span>childNodes</span><span data-sanitized-class="token punctuation">&gt;</span></span>foo</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">id</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span>childNodes</span><span data-sanitized-class="token punctuation">&gt;</span></span>bar</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>input</span> <span data-sanitized-class="token attr-name">type</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span>text</span> <span data-sanitized-class="token attr-name">value</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>hidden-from-js<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>form</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>These injected input elements will overwrite the <code>form</code> element's property and all following JavaScript code will <strong>not</strong> be able to iterate over <code>f.childNodes</code>!</p>
<p>Compare the clobbered property with the actual children in this screenshot below:</p>
<p><img src="https://htmhell.dev/images/advent2022/6/image1.png" alt=""></p>
<p>Do you see the difference in length?</p>
<p>An attack vector like this one could be used to fool or confuse the website's JavaScript code when iterating over attacker-controlled DOM trees.</p>
<p>Just imagine what else could be overridden!</p>
<p>How would your web page behave if seemingly innocent function calls like <code>document.getElementById()</code> can fail with "Uncaught TypeError: <code>document.getElementById</code> is not a function" because the API has also been clobbered</p>
<h3 data-sanitized-id="prevention">Prevention</h3>
<p>The best way to prevent DOM Clobbering is to use a strong <a href="https://en.wikipedia.org/wiki/HTML_sanitization">Sanitizer</a> library. A sanitizer typically goes through user-supplied HTML and only leaves the harmless bits - removing scripts, event handlers and other injections - like DOM Clobbering.</p>
<p>The author of this article recommends <a href="https://github.com/cure53/DOMPurify/">DOMPurify</a>. By default, DOMPurify will remove all clobbering properties. Using the option <code>SANITIZE_NAMED_PROPS: true</code> will instead prefix user-supplied identifiers with <code>user-content-</code>.</p>
<p>However, if you want to live on the edge you might also want to look at the upcoming <a href="https://wicg.github.io/sanitizer-api/">Sanitizer API</a>. The specification for the Sanitizer API is still in development, but Chrome and Firefox are already shipping a prototype and the <a href="https://sanitizer-api.dev/">Sanitizer API Playground</a> has instructions on how to enable it.</p>
<p>In order to fix DOM Clobbering with the Sanitizer API, you need to configure the Sanitizer to disallow attributes of type <code>name</code> and <code>id</code>:</p>
<pre data-sanitized-class="language-js"><code data-sanitized-class="language-js"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token keyword">const</span> mySanitizer <span data-sanitized-class="token operator">=</span> <span data-sanitized-class="token keyword">new</span> <span data-sanitized-class="token class-name">Sanitizer</span><span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">  blockAttributes<span data-sanitized-class="token operator">:</span> <span data-sanitized-class="token punctuation">[</span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token punctuation">{</span><span data-sanitized-class="token string">'name'</span><span data-sanitized-class="token operator">:</span> <span data-sanitized-class="token string">'id'</span><span data-sanitized-class="token punctuation">,</span> elements<span data-sanitized-class="token operator">:</span> <span data-sanitized-class="token string">'*'</span><span data-sanitized-class="token punctuation">}</span><span data-sanitized-class="token punctuation">,</span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token punctuation">{</span><span data-sanitized-class="token string">'name'</span><span data-sanitized-class="token operator">:</span> <span data-sanitized-class="token string">'name'</span><span data-sanitized-class="token punctuation">,</span> elements<span data-sanitized-class="token operator">:</span> <span data-sanitized-class="token string">'*'</span><span data-sanitized-class="token punctuation">}</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token punctuation">]</span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token punctuation">}</span><span data-sanitized-class="token punctuation">)</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">someElement<span data-sanitized-class="token punctuation">.</span><span data-sanitized-class="token function">setHTML</span><span data-sanitized-class="token punctuation">(</span>input<span data-sanitized-class="token punctuation">,</span> <span data-sanitized-class="token punctuation">{</span>sanitizer<span data-sanitized-class="token operator">:</span> mySanitizer<span data-sanitized-class="token punctuation">}</span><span data-sanitized-class="token punctuation">)</span><span data-sanitized-class="token punctuation">;</span></span></code></pre>
<p>Good luck!</p>


