# entry

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://christitus.com/docker-guide/
title: Docker Guide
link: https://christitus.com/docker-guide/
hash: v�k0!�1ԘpB}��
attributes: {"enclosures":[]}
content:
<p>This is a full walk-through and guide for Docker.</p>
<h2 data-sanitized-id="install-and-getting-started">Install and Getting Started</h2>
<ul>
<li>Official Docker: <a href="https://docs.docker.com/get-docker/">https://docs.docker.com/get-docker/</a></li>
<li>Official Portainer: <a href="https://docs.portainer.io/start/install/server/docker">https://docs.portainer.io/start/install/server/docker</a></li>
</ul>
<h2 data-sanitized-id="quick-commands">Quick Commands</h2>
<h3 data-sanitized-id="run-a-new-container">Run a new container</h3>
<ul>
<li>New Image - <code>docker run IMAGE</code></li>
<li>Name Container and Launch Image - <code>docker run --name CONTAINER IMAGE</code></li>
<li>Map Container Ports and Launch Image -<code>docker run -p HOSTPORT:CONTAINERPORT IMAGE</code></li>
<li>Map ALL Ports and Launch Image - <code>docker run -P IMAGE</code></li>
<li>Launch Image as Background Service - <code>docker run -d IMAGE</code></li>
<li>Map Local Directory and Launch - <code>docker run -v HOSTDIR:TARGETDIR IMAGE</code></li>
</ul>
<h3 data-sanitized-id="manage-containers">Manage Containers</h3>
<ul>
<li>List RUNNING Containers - <code>docker ps</code></li>
<li>List ALL containers - <code>docker ps -a</code></li>
<li>Delete container - <code>docker rm CONTAINER</code></li>
<li>Delete a Running Container - <code>docker rm -f CONTAINER</code></li>
<li>Stop Container - <code>docker stop CONTAINER</code></li>
<li>Start Container - <code>docker start CONTAINER</code></li>
<li>Copy File FROM container - <code>docker cp CONTAINER:SOURCE TARGET</code></li>
<li>Copy File TO container - <code>docker cp TARGET CONTAINER:SOURCE</code></li>
<li>Start Shell inside container - <code>docker exec -it CONTAINER bash</code></li>
<li>Rename container - <code>docker rename OLD NEW</code></li>
<li>Create new Image from Container - <code>docker commit CONTAINER</code></li>
</ul>
<h3 data-sanitized-id="manage-images">Manage Images</h3>
<ul>
<li>Download Image - <code>docker pull IMAGE[:TAG]</code></li>
<li>Upload Image to repository - <code>docker push IMAGE</code></li>
<li>Delete Image - <code>docker rmi IMAGE</code></li>
<li>List Images - <code>docker images</code></li>
<li>Build Image from Docker file - <code>docker build DIRECTORY</code></li>
<li>Tag Image IMAGE - <code>docker tag IMAGE NEWIMAGE:TAG</code></li>
</ul>
<h3 data-sanitized-id="troubleshooting-and-information">Troubleshooting and Information</h3>
<ul>
<li>Show logs - <code>docker logs CONTAINER</code></li>
<li>Show stats - <code>docker stats</code></li>
<li>Show processes - <code>docker top CONTAINER</code></li>
<li>Show modified files - <code>docker diff CONTAINER</code></li>
<li>Show mapped ports - <code>docker port CONTAINER</code></li>
</ul>
<h2 data-sanitized-id="walkthrough-video">Walkthrough Video</h2>
<div>
<iframe allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/94VQvRpjfO8?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" title="YouTube video" sandbox="allow-scripts allow-same-origin"></iframe>
</div>


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://christitus.com/screensavers/
title: Screensavers
link: https://christitus.com/screensavers/
hash: �"��N�ZòR*m6 ��
attributes: {"enclosures":[]}
content:
<p>Screensavers might be the past, but they are still one of the coolest to do on your PC.</p>
<blockquote data-sanitized-class="twitter-tweet"><p lang="en" dir="ltr">Love this screensaver. Still the best of all time imo. <a href="https://t.co/vv16kPECZL">https://t.co/vv16kPECZL</a></p>— Chris Titus Tech (@christitustech) <a href="https://twitter.com/christitustech/status/1594450349657821186?ref_src=twsrc%5Etfw">November 20, 2022</a></blockquote>

<h2 data-sanitized-id="scr-file-screensavers">SCR File Screensavers</h2>
<ul>
<li>System47 SCR File - <a href="https://www.mewho.com/system47/">https://www.mewho.com/system47/</a>
<img loading="lazy" src="https://christitus.com/images/2022/starfield-screensaver/system47.webp" alt="" data-sanitized-class="img-fluid"> </li>
<li><a href="https://learn.microsoft.com/en-us/sysinternals/downloads/bluescreen">Microsoft BSOD</a></li>
<li><a href="https://www.screensaversplanet.com/screensavers/?free=on">Screensavers Website</a></li>
</ul>
<h2 data-sanitized-id="website-screensavers">Website Screensavers</h2>
<ul>
<li>
<p><a href="https://www.mewho.com/starfield47/">Starfield meWho</a>
<img loading="lazy" src="https://christitus.com/images/2022/starfield-screensaver/starfield.webp" alt="" data-sanitized-class="img-fluid"> </p>
</li>
<li>
<p><a href="https://gradiyent.netlify.app/">Gradient Colors</a>
<img loading="lazy" src="https://christitus.com/images/2022/starfield-screensaver/gradient.webp" alt="" data-sanitized-class="img-fluid"> </p>
</li>
<li>
<p><a href="https://sourceforge.net/projects/rssavers/">Really Slick Screensavers</a>
<img loading="lazy" src="https://christitus.com/images/2022/starfield-screensaver/hyperspace.webp" alt="" data-sanitized-class="img-fluid"> </p>
</li>
<li>
<p><a href="https://www.ravbug.com/bsod/">Fake BSODs</a>
<img loading="lazy" src="https://christitus.com/images/2022/starfield-screensaver/bsod.webp" alt="" data-sanitized-class="img-fluid"> </p>
</li>
<li>
<p><a href="https://www.cryptoprank.com/#/">Crypto Prank</a>
<img loading="lazy" src="https://christitus.com/images/2022/starfield-screensaver/crypto-prank.webp" alt="" data-sanitized-class="img-fluid"> </p>
</li>
<li>
<p><a href="https://fakeupdate.net/">Fake Updates</a></p>
<p><img loading="lazy" src="https://christitus.com/images/2022/starfield-screensaver/xp.webp" alt="" data-sanitized-class="img-fluid"> </p>
</li>
<li>
<p><a href="https://screen.vercel.app/">Fake Screens</a></p>
</li>
<li>
<p><a href="https://updatefaker.com/">Update Faker</a></p>
</li>
</ul>
<h2 data-sanitized-id="load-screen-savers">Load Screen Savers</h2>
<h3 data-sanitized-id="windows">Windows</h3>
<ol>
<li>Copy the *.scr file to <code>c:\Windows\System32</code></li>
<li>Launch the Screensaver Windows Module (Start -&gt; Run -&gt; <code>control desk.cpl,,@screensaver</code>)</li>
<li>Select the screensaver you copied</li>
</ol>
<p>Copy/Paste Run command:</p>
<div data-sanitized-class="highlight"><pre tabindex="0" data-sanitized-class="chroma"><code data-lang="fallback" data-sanitized-class="language-fallback"><span data-sanitized-class="line"><span data-sanitized-class="cl">control desk.cpl,,@screensaver
</span></span></code></pre></div><h3 data-sanitized-id="linux">Linux</h3>
<p>Loading scr files on Linux requires you to use WINE. You can launch this using wine.exe, but here is my article on setting it up as a systemd service: <a href="https://christitus.com/lcars-screensaver/">https://christitus.com/lcars-screensaver/</a></p>
<h2 data-sanitized-id="walkthrough-video">Walkthrough Video</h2>
<div>
<iframe allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/V7aKCCfmJww?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" title="YouTube video" sandbox="allow-scripts allow-same-origin"></iframe>
</div>


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>


guid: https://htmhell.dev/adventcalendar/2022/13/
title: One day we'll have a fully customisable select
author: ;Manuel Matuzovic
link: https://htmhell.dev/adventcalendar/2022/13/
hash: �E�L��SUN3 E`
attributes: {"enclosures":[]}
content:
<p>Today, I want to  look at a proposed HTML feature that may end up replacing a lot of <code>&lt;div&gt;</code>s-based custom input components: <code>&lt;selectmenu&gt;</code>.</p>
<h2 data-sanitized-id="css-is-awesome">CSS <em>is</em> awesome</h2>
<p>I realise this calendar is about HTML. And I'll get to that. But first, let me start with CSS. CSS is fantastic, because it has allowed us to decide what our websites look like for over 25 years. This wasn't a given. Before CSS, you could only define the structure of your pages and browsers would decide their appearance.</p>
<p>Fast-forward to today, CSS not only exists, it has become extremely versatile. We have grids, custom properties, transforms and much more, and it is all pretty compatible across different browsers. The basic principle of CSS stays: styles are hints. What websites look like is a combination of the preferences of users, browsers and web developers.</p>
<p>But maybe in your design system, your select has a very specific style. Shadows  around the listbox, brand-specific whitespace settings… or your select contains more than just strings of text, like flags with country names or avatars with user names. The <code>&lt;select&gt;</code> element won't let you go that far with CSS. Enter <code>&lt;selectmenu&gt;</code>.</p>
<h2 data-sanitized-id="the-parts-of-lessselectmenugreater">The parts of <code>&lt;selectmenu&gt;</code></h2>
<p>The <a href="https://open-ui.org/prototypes/selectmenu/"><code>&lt;selectmenu&gt;</code> element</a> is a new HTML element proposed by the <a href="https://open-ui.org/">Open UI Community Group</a>. It has not yet landed in the <a href="https://html.spec.whatwg.org/">HTML Specification</a>, but it is being prototyped in <a href="https://www.chromium.org/Home/">Chromium</a>. You can test it by turning the “Experimental Web Platform Features” flag on (go to about:flags and search for this flag).</p>
<p>When you use a <code>&lt;selectmenu&gt;</code>, you'll find it is comprised out of different parts:</p>
<p><img src="https://htmhell.dev/images/advent2022/13/parts.jpg" alt="rendering of a selectmenu with arrows pointing to its individual parts; the closed part is called button, the icon within it marker, the value within it selected-value and the expanding part listbox"></p>
<ul>
<li><code>&lt;select&gt;</code> - the root element</li>
<li><code>&lt;button&gt;</code> - the button you click to open the select</li>
<li><code>&lt;selected-value&gt;</code> - the currently selected value</li>
<li><code>&lt;marker&gt;</code> - the arrow that is in the button</li>
<li><code>&lt;listbox&gt;</code> - the popover that opens when you click the button</li>
<li><code>&lt;option&gt;</code> - the options within the listbox (just like in regular <code>&lt;select&gt;</code>)</li>
<li><code>&lt;optgroup&gt;</code> - an optional way of grouping options (just like in regular <code>&lt;select&gt;</code>)</li>
</ul>
<p>From: <a href="https://open-ui.org/prototypes/selectmenu">Anatomy of the selectmenu</a></p>
<h2 data-sanitized-id="styling-lessselectmenugreater">Styling <code>&lt;selectmenu&gt;</code></h2>
<h3 data-sanitized-id="styling-parts">Styling parts</h3>
<p>In <a href="https://www.w3.org/TR/css-shadow-parts-1/">CSS Shadow Parts 1</a>, currently a Working Draft (eg <a href="https://www.w3.org/2021/Process-20211102/#rec-track">not yet a full-blown standard</a>), a new pseudo element is introduced to allow styling parts of shadow roots: <code>::part()</code>.</p>
<p>Wait, wasn't Shadow DOM something Web Components-specific? Yes. But how  <code>&lt;selectmenu&gt;</code> is implemented in the browser, is kind of Web Component-like. You could see it as a Web Component that ships with the browser.</p>
<p>With <code>::part</code>, you can style the different parts as they are described above, for instance, to style the listbox, you would do:</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">selectmenu::part(listbox)</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">box-shadow</span><span data-sanitized-class="token punctuation">:</span> 3px 3px 3px 3px hotpink<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>Or maybe you want to change what the arrow looks like:</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">selectmenu::part(marker)</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">box-shadow</span><span data-sanitized-class="token punctuation">:</span> 3px 3px 3px 3px hotpink<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>(The <code>&lt;marker&gt;</code>  is not yet added to the selectmenu explainer, but it was <a href="https://github.com/openui/open-ui/issues/548#issuecomment-1262650219">confirmed in an Open UI meeting</a></p>
<h3 data-sanitized-id="styling-states">Styling states</h3>
<p>You will also be able to style a selectmenu based on whether it is open or closed, using the <code>:open</code> pseudo class:</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">selectmenu</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">border</span><span data-sanitized-class="token punctuation">:</span> 2px solid black<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">selectmenu:open</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">border-color</span><span data-sanitized-class="token punctuation">:</span> hotpink<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>Or maybe you want a different marker when it is open:</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">selectmenu::part(marker)</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">// regular</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">selectmenu::part(marker):open</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">// open</span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token punctuation">}</span></span></code></pre>
<img src="https://htmhell.dev/images/advent2022/13/openclosed.jpg" loading="lazy" alt="two selectboxes, the first is closed, the second is open. the closed one has selector selectmenu::part(marker):closed, the open one has selectmenu::part(marker):open">
<p><em>Different icons on opened and closed states</em></p>
<p>There will also be a <code>:closed</code> pseudo class, to style the closed state. It would be equivalent to <code>:not(:open)</code>. The <code>:open</code> and <code>:closed</code> pseudos are defined in the <a href="https://www.w3.org/TR/selectors/#open-state">Element Display State section of Selectors, Level 4</a>.</p>
<h2 data-sanitized-id="customising-beyond-just-styling">Customising beyond just styling</h2>
<p>You can also replace the parts shown above with random markup of your own. The parts shown above are exposed as “slots”, meaning you can add your own tree structure in your markup and use that to replace a part.</p>
<p>For instance, this is how you  would replace the icon with something else:</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>selectmenu</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">slot</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>marker<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 comment">&lt;!-- your own selectmenu open icon goes here --&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>div</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>selectmenu</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>This uses whatever is inside this <code>div</code> instead of the default marker in the button to open a selectmenu.</p>
<p>In principle, <code>&lt;selectmenu&gt;</code> will allow you to do things like this with each of the parts, so that you could replace the button or the options. This gives developers a lot of power,  and with that comes responsibility. So a word of warning: nesting the wrong kind of elements into parts can quickly lead to a “HTMHell”. For instance, what if you put more than just text inside of an <code>option</code>—say, avatars—but browsers and assistive technologies expect just text? Or what if you put a <code>button</code> in an <code>option</code>? Nested interactive elements like that risk breaking the experience for end users, in ways that the browser or assistive technologies can't magically fix, so beware.</p>
<h2 data-sanitized-id="current-status">Current status</h2>
<p>Selectmenu is currently being “incubated” at the Open UI Community Group and prototyped behind a flag in Chromium.</p>
<p>What about other browsers and browser engines? I'm not sure what will happen in Safari or Webkit, but folks from Firefox (Mozilla) join the Open UI calls. Quoting from the “The Declarative Web” part of Mozilla's vision for the open web:</p>
<blockquote>[on the web, built-in controls are] often insufficiently styleable and have inconsistent internal structures across browsers, which makes it difficult to make them visually consistent with the rest of the Web page. We want to fill these gaps, and are pleased to see the OpenUI effort already making progress in this space.</blockquote>
<p>For <code>&lt;selectmenu&gt;</code> to become a reality, it would need to go into the standards and then get browser implementations. At this time, it's hard to say when that will be the case.</p>
<h2 data-sanitized-id="summary">Summary</h2>
<p>So, in summary: <code>&lt;selectmenu&gt;</code> is a new proposal that would add a new control to the web platform that is like <code>&lt;select&gt;</code> by default, but can be styled and customised in pretty much any way you want. I'm particularly excited about the ability to use <code>::part()</code> to style parts, and slightly worried about the ability to replace parts completely as that may break accessibility if it is replaced with the wrong things.</p>
<p>You can play with <code>&lt;selectmenu&gt;</code> today in Microsoft Edge Canary or Google Chrome Canary and <a href="https://github.com/openui/open-ui/issues/new">file issues</a> against the Open UI repository.</p>


guid: https://christitus.com/install-windows-update-powershell/
title: Install Windows Update Powershell
link: https://christitus.com/install-windows-update-powershell/
hash: �쒘ao�3Dy � �+6
attributes: {"enclosures":[]}
content:
<p>Did you know you can install updates with using PowerShell? This is the Guide for doing that!</p>
<h2 data-sanitized-id="pre-requisites">Pre-requisites</h2>
<p>To install Windows updates via PowerShell, you need to install the module first:</p>
<div data-sanitized-class="highlight"><pre tabindex="0" data-sanitized-class="chroma"><code data-lang="fallback" data-sanitized-class="language-fallback"><span data-sanitized-class="line"><span data-sanitized-class="cl">Install-Module PSWindowsUpdate
</span></span><span data-sanitized-class="line"><span data-sanitized-class="cl">Add-WUServiceManager -MicrosoftUpdate
</span></span></code></pre></div><h2 data-sanitized-id="commands">Commands</h2>
<p>Install all available updates</p>
<div data-sanitized-class="highlight"><pre tabindex="0" data-sanitized-class="chroma"><code data-lang="fallback" data-sanitized-class="language-fallback"><span data-sanitized-class="line"><span data-sanitized-class="cl">Install-WindowsUpdate -MicrosoftUpdate -AcceptAll -AutoReboot | Out-File "C:\($env.computername-Get-Date -f yyyy-MM-dd)-MSUpdates.log" -Force
</span></span></code></pre></div><p>Force other computers to update</p>
<div data-sanitized-class="highlight"><pre tabindex="0" data-sanitized-class="chroma"><code data-lang="fallback" data-sanitized-class="language-fallback"><span data-sanitized-class="line"><span data-sanitized-class="cl">$Computers = "pc2,pc3,pc4"
</span></span><span data-sanitized-class="line"><span data-sanitized-class="cl">Invoke-WUJob -ComputerName $Computers -Script {Import-Module PSWindowsUpdate; Install-WindowsUpdate -MicrosoftUpdate -AcceptAll -AutoReboot} -RunNow -Confirm:$false | Out-File "c:\$Computers-$(Get-Date -f yyyy-MM-dd)-MSUpdates.log" -Force
</span></span></code></pre></div><h2 data-sanitized-id="walkthrough-video">Walkthrough Video</h2>
<div>
<iframe allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/M2mMQfPGZsE?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" title="YouTube video" sandbox="allow-scripts allow-same-origin"></iframe>
</div>


guid: https://htmhell.dev/adventcalendar/2022/14/
title: Table Like It's 2023
author: ;Manuel Matuzovic
link: https://htmhell.dev/adventcalendar/2022/14/
hash: 93[�a-�����u��
attributes: {"enclosures":[]}
content:
<p>In this article:</p>
<ul>
<li><a href="https://htmhell.dev/adventcalendar/2022/14/#hello-website-builders!">Hello, Website Builders!</a></li>
<li><a href="https://htmhell.dev/adventcalendar/2022/14/#a-little-history">A little history</a></li>
<li><a href="https://htmhell.dev/adventcalendar/2022/14/#what-is-a-table?">What is a table?</a></li>
<li><a href="https://htmhell.dev/adventcalendar/2022/14/#who-benefits-from-tables?">Who benefits from tables?</a></li>
<li><a href="https://htmhell.dev/adventcalendar/2022/14/#what-does-a-table-look-like?">What does a table look like?</a></li>
<li><a href="https://htmhell.dev/adventcalendar/2022/14/#what-does-a-table-sound-and-feel-like?">What does a table sound and feel like?</a></li>
<li><a href="https://htmhell.dev/adventcalendar/2022/14/#(re)learning-tables-(1994-2022)">(Re)learning tables (1994 - 2022)</a></li>
<li><a href="https://htmhell.dev/adventcalendar/2022/14/#wcag-levels-unlocked">WCAG levels unlocked</a></li>
<li><a href="https://htmhell.dev/adventcalendar/2022/14/#when-tables-get-complicated">When tables get complicated</a></li>
<li><a href="https://htmhell.dev/adventcalendar/2022/14/#go-forth-and-make-good-tables">Go forth, and make good tables</a></li>
<li><a href="https://htmhell.dev/adventcalendar/2022/14/#learn-html-(including-tables)-for-free">Learn HTML (including tables) for free</a></li>
<li><a href="https://htmhell.dev/adventcalendar/2022/14/#testing-tools">Testing tools</a></li>
<li><a href="https://htmhell.dev/adventcalendar/2022/14/#special-thanks">Special thanks</a></li>
<li><a href="https://htmhell.dev/adventcalendar/2022/14/#about-amy-carney">About Amy</a></li>
</ul>
<h2 data-sanitized-id="hello-website-builders!">Hello, Website Builders!</h2>
<p>Hey, you. Yes, you. Let's talk about tables on the web.</p>
<p>It's almost 2023. Yet tabular data is still being delivered in ways that aren't accessible. From a visually disabled person's perspective, it's horrifying.</p>
<p>Data tables aren't given semantic HTML to clarify its information relationships. Table markup is still used for page layouts, yet they're aren't flagged as such. The <a href="https://almanac.httparchive.org/en/2022/accessibility#tables">Web Alamanac</a> reported how infrequent <code>caption</code> (a table's title) and <code>role=presentation</code> (indicating layout-only) were used in 2022 to improve accessibility.</p>
<p>I'm embarrassed on behalf of my fellow developers, who should be more up-to-date with their craft and aware of current standards and best practices. My hope is to persuade you to make better choices as you build your website.</p>
<h2 data-sanitized-id="a-little-history">A little history</h2>
<p><a href="http://www.barrypearson.co.uk/articles/layout_tables/history.htm">Table markup has been available since 1994</a>, despite not being an <a href="https://www.w3.org/TR/2018/SPSD-html32-20180315/#table">official HTML 3.2 recommendation</a> until 1997. If you were writing front-end code at that time, you probably did what a lot of us did: use <code>table</code> for layout AND tabular data. We didn't have many alternatives then. It didn't help that the specification stated that tables could be used for "layout purposes."</p>
<p>But that was then. We have better options now. HTML 4.01 gave us separate stylesheets. CSS iterations have given us multiple ways to layout pages, including:</p>
<ul>
<li>CSS grid,</li>
<li>flexbox,</li>
<li>multi-columns, and</li>
<li>positioning rules.</li>
</ul>
<p>Yet, 28 years later, the inaccessible tables I've seen (and remediated) have me scratching my head. Are today's developers learning from old knowledge delivered in tutorials and Stack Overflow answers? Despite reliable, easy-to-access resources, like <a href="https://developer.mozilla.org/en-US/">MDN (Mozilla Developer's Network)</a>, table and data abuse are still happening.</p>
<h2 data-sanitized-id="what-is-a-table?">What is a table?</h2>
<p>To know when and how to use a table, you need to understand what a table is. A table is for tabular data.</p>
<p>WHATWG's (Web Hypertext Application Technology Working Group) <a href="https://html.spec.whatwg.org/multipage/tables.html#tables">HTML Living Standard states about tables</a>, "The table represents data with more than one dimension, in the form of a table."</p>
<p>If you're less familiar with the HTML Living Standard, you may recognize MDN. <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table">MDN describes an HTML table</a> as, "tabular data — that is, information presented in a two-dimensional table comprised of rows and columns of cells containing data."</p>
<h2 data-sanitized-id="who-benefits-from-tables?">Who benefits from tables?</h2>
<p>Ok, maybe you already <em>know</em> what a table is.</p>
<p>But do you know who benefits from proper table markup and styling? By "proper table markup", I mean the <code>table</code> element, not <code>div</code> or <code>img</code> elements.</p>
<p>Generally, people with visual and cognitive disabilities benefit.</p>
<p>Specifically, people who:</p>
<ul>
<li>use a screen reader,</li>
<li>magnify their screen,</li>
<li>use Windows High Contrast Mode,</li>
<li>use dark mode,</li>
<li>use custom stylesheets,</li>
<li>copy &amp; paste,</li>
<li>import data into other programs, and</li>
<li>save pages as PDFs.</li>
</ul>
<p>To be honest, I'm hard-pressed to find anyone who doesn't benefit from thoughtful markup and styling of table data.</p>
<h2 data-sanitized-id="what-does-a-table-look-like?">What does a table look like?</h2>
<p>By this point, we know a table looks like a 2D grid of rows and columns. Is there more to consider? Yes!</p>
<p>We want to help people make visual sense of a table. To be more inclusive, content creators, designers, and developers should evaluate their choices when it comes to:</p>
<ul>
<li>contrast between background color and foreground text,</li>
<li>font family, size, and spacing,</li>
<li>border visibility, color, and thickness,</li>
<li>color choices that can be overwritten by custom stylesheets and Windows High Contrast Mode, and</li>
<li>hover-activated changes that exclude keyboard and mobile device users.</li>
</ul>
<p>As someone visually disabled, who needs strong contrast and screen magnification, I need borders that stand out. When I magnify my screen, a solid line guides me along each row. As I rely on strong contrast between background, border, and text, I need borders and backgrounds to <em>not</em> be a light gray. Not to mention, if I use Windows High Contrast Mode that day, your background colors will disappear.</p>
<h2 data-sanitized-id="what-does-a-table-sound-and-feel-like?">What does a table sound and feel like?</h2>
<p>But what about people who don't rely on visual cues? Specifically, people who rely on text-to-speech (screenreader) software to read content and convey the context of the content (headings, tables, images, etc.).</p>
<h3 data-sanitized-id="screen-reader-semantics">Screen reader semantics</h3>
<p>A table is self-explanatory by conveying its child relationships between data points. Cells are associated with the column and row they sit in. HTML elements have this accessibility built-in.</p>
<p>I highly recommend you watch Léonie Watson's demonstration "How screen readers navigate data tables", approximately 2 minutes to watch.</p>
<div data-sanitized-class="video">
<iframe width="560" height="315" src="https://www.youtube.com/embed/X1KR4u94cho" title="YouTube video player" frameborder="0" allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" sandbox="allow-scripts allow-same-origin"></iframe>
</div>
<p>You should also read her <a href="https://tink.uk/how-screen-readers-navigate-data-tables/">accompanying blog post about how screen readers navigate data tables</a>.</p>
<h3 data-sanitized-id="screen-reader-keyboard-shortcuts">Screen reader keyboard shortcuts</h3>
<p>Did you know screen readers allow users to navigate with keyboard shortcuts? They can jump from table to table and interact with columns, rows, and cells within a table.</p>
<p>WebAIM provides helpful instructions on how to get started to test with a screen reader:</p>
<ul>
<li><a href="https://webaim.org/articles/jaws/">Using JAWS to Evaluate Web Accessibility</a></li>
<li><a href="https://webaim.org/articles/nvda/">Using NVDA to Evaluate Web Accessibility</a></li>
<li><a href="https://webaim.org/articles/voiceover/">Using VoiceOver to Evaluate Web Accessibility</a>:</li>
</ul>
<p>If you need a better sense of which screen readers are used the most, checkout <a href="https://webaim.org/projects/screenreadersurvey9/#primary">WebAIM's latest Screen Reader User Survey</a>.</p>
<p>Don't forget about mobile screen reader users. They have access to touch gestures to quickly jump between tables and navigate within a table, too. But some mobile device users pair their phone or tablet with a keyboard, giving them access to keyboard commands.</p>
<h3 data-sanitized-id="learn-more-about-the-screen-reader-users-experience">Learn more about the screen reader user's experience</h3>
<p>Feel intimidated by screen readers? Check out these resources to get an introduction to screen readers and how people use them:</p>
<ul>
<li><a href="https://webaim.org/techniques/screenreader/">Designing for Screen Reader Compatibility</a></li>
<li><a href="https://youtu.be/8Rn5pXCdZWU">W3C Web Accessibility Perspectives: Text to Speech (YouTube)</a></li>
</ul>
<p>Your markup choices can make or break a user's experience.</p>
<h2 data-sanitized-id="(re)learning-tables-(1994-2022)">(Re)learning tables (1994 - 2022)</h2>
<p>This is my largest section, by far. If you feel you need to move forward, here is my TL;DR (too long, didn't read):</p>
<ul>
<li>It's <strong>OK</strong> to use <code>table</code> in 2023! Make that tabular data make sense to everyone.</li>
<li>It's <strong>not</strong> OK to arrange tabular data in <code>div</code>s and <code>span</code>s, or other unrelated markup.</li>
<li>It's <strong>not</strong> OK to use an <code>img</code> of a table, which is inaccessible for many folks.</li>
<li>Update your table model knowledge; some elements and attributes have changed in the past 28 years.</li>
</ul>
<p>If you're still with me, here we go.</p>
<p>As I said, a lot has changed since 1994. We have more HTML elements to construct more meaningful (context for content) webpages. Styles have broken free from the building blocks of HTML to create a separate layer of aesthetics.</p>
<h3 data-sanitized-id="when-should-you-use-a-table?">When should you use a table?</h3>
<p>Maybe you're still torn about if you should use a table or not.</p>
<p>Here's a few questions you can ask yourself:</p>
<ul>
<li>Do I have tabular data (grid of items related to one another)?</li>
<li>Do I have an image (<code>img</code>) of a table?</li>
<li>Does my table element have a <code>role=presentation</code> attribute on it?</li>
<li>Does my table use obsolete attributes, like <code>border</code>, <code>cellspacing</code>, or <code>cellpadding</code> with a value of 0?</li>
</ul>
<p>If you said, "yes" to the first two items, then you probably should use <code>table</code>. If you said, "yes" to the last two items, you probably should use CSS to design your layout instead.</p>
<p>Speaking of CSS, today we have the advantage of separating architecture from aesthetics. Several HTML table attributes are now obsolete, to be replaced by CSS properties. Let's dive into the HTML building blocks, then bring up the decorative part again.</p>
<h3 data-sanitized-id="how-to-markup-tables">How to markup tables</h3>
<p>Ready to make that table now?</p>
<p>Let the HTML Living Standard be your guide:</p>
<p>"Expected children [of the table model] include, in this order:</p>
<ol>
<li>optionally a <code>caption</code> element,</li>
<li>followed by zero or more <code>colgroup</code> elements,</li>
<li>followed optionally by a <code>thead</code> element,</li>
<li>followed by either zero or more <code>tbody</code> elements OR one or more <code>tr</code> elements,</li>
<li>followed optionally by a <code>tfoot</code> element, optionally intermixed with one or more script-supporting elements."</li>
</ol>
<p>What does that look like for those who write or generate HTML?</p>
<pre data-sanitized-class="language-html"><code data-sanitized-class="language-html"><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>table</span><span data-sanitized-class="token punctuation">&gt;</span></span> <span data-sanitized-class="token comment">&lt;!-- required --&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>caption</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>caption</span><span data-sanitized-class="token punctuation">&gt;</span></span> <span data-sanitized-class="token comment">&lt;!-- optional, but ensure table has an accessible name --&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>colgroup</span><span data-sanitized-class="token punctuation">&gt;</span></span> <span data-sanitized-class="token comment">&lt;!-- 0 or more --&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>col</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>col</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>col</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>col</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>col</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>col</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>colgroup</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>thead</span><span data-sanitized-class="token punctuation">&gt;</span></span> <span data-sanitized-class="token comment">&lt;!-- thead optional --&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>tr</span><span data-sanitized-class="token punctuation">&gt;</span></span> <span data-sanitized-class="token comment">&lt;!-- tr required --&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>th</span> <span data-sanitized-class="token attr-name">scope</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>row<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>th</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>td</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>td</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>tr</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>thead</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>tbody</span><span data-sanitized-class="token punctuation">&gt;</span></span> <span data-sanitized-class="token comment">&lt;!-- tbody optional, 0 or more --&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>tr</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>th</span> <span data-sanitized-class="token attr-name">scope</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>row<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>td</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>td</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>td</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>tr</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>tbody</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>tfoot</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>tfoot</span><span data-sanitized-class="token punctuation">&gt;</span></span> <span data-sanitized-class="token comment">&lt;!-- tfoot optional --&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>table</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line"></span></code></pre>
<h3 data-sanitized-id="a-note-about-table-model-elements">A note about table model elements</h3>
<p>If you started coding tables in the 1990s, you may feel that table markup was simpler then. Did you know <a href="https://www.w3.org/TR/html4/">HTML 4.01</a> introduced new elements for row and column groups to the table model?</p>
<p>If you haven't already, consider adding these elements (from the HTML Living Standard) to your toolbox:</p>
<ul>
<li><a href="https://html.spec.whatwg.org/#the-colgroup-element">colgroup</a></li>
<li><a href="https://html.spec.whatwg.org/#the-col-element">col</a></li>
<li><a href="https://html.spec.whatwg.org/#the-thead-element">thead</a></li>
<li><a href="https://html.spec.whatwg.org/#the-tbody-element">tbody</a></li>
<li><a href="https://html.spec.whatwg.org/#the-tfoot-element">tfoot</a></li>
</ul>
<p>The ability to group rows and columns are useful for granular styling or organization of data. They are not essential for accessibility at this time.</p>
<h3 data-sanitized-id="a-note-on-deprecated-attributes">A note on deprecated attributes</h3>
<p>Even in 2022, I've seen old attributes hanging around that have been dumped in the obsolete bin. It's time for a markup refresh, if you're still using obsolete attributes.</p>
<table>
  <caption>Obsolete (deprecated) table attributes</caption>
  <thead>
    <tr>
      <th scope="col">Elements</th>
      <th scope="col">Attributes</th>
    </tr><tr>
  </tr></thead>
  <tbody>
    <tr>
      <td>table</td>
      <td>align, bgcolor, border, cellspacing, cellpadding, frame, rules, summary, width</td>
    </tr>
    <tr>
      <td>caption</td>
      <td>align, valign</td>
    </tr>
    <tr>
      <td>colgroup</td>
      <td rowspan="4">align, bgcolor, char, charoff, valign</td>
    </tr>
    <tr>
      <td>thead</td>
    </tr>
    <tr>
      <td>tbody</td>
    </tr>
    <tr>
      <td>tfoot</td>
    </tr>
    <tr>
      <td>tr</td>
      <td>align, bgcolor, char, charoff, valign</td>
    </tr>
    <tr>
      <td>th</td>
      <td rowspan="2">align, nowrap, valign, width, height</td>
    </tr>
    <tr>
      <td>td</td>
    </tr>
  </tbody>
</table>
<p><a data-sanitized-id="wcag"></a></p>
<h2 data-sanitized-id="wcag-levels-unlocked">WCAG levels unlocked</h2>
<p>The appropriate use of the <code>table</code> element now welcomes everyone to your site and app. But you get something out of it, too! Your project has come further in achieving accessibility success and unlocking new levels of the Web Content Accessibility Guidelines (WCAG).</p>
<p>Here are some WCAG success criteria (SC) you've managed to tackle with your user-driven approach:</p>
<ul>
<li><a href="https://www.w3.org/WAI/WCAG21/Understanding/info-and-relationships.html">Info and Relationships (1.3.1, Level A)</a></li>
<li><a href="https://www.w3.org/WAI/WCAG21/Understanding/meaningful-sequence.html">Meaningful Sequence (1.3.2, Level A)</a></li>
<li><a href="https://www.w3.org/WAI/WCAG21/Understanding/parsing.html">Parsing (4.1.1, Level A)</a></li>
</ul>
<p>Depending on your content, design, table width, and approach, you <em>may</em> have even covered:</p>
<ul>
<li><a href="https://www.w3.org/WAI/WCAG21/Understanding/resize-text.html">Resize Text (1.4.4, Level AA)</a></li>
<li><a href="https://www.w3.org/WAI/WCAG21/Understanding/images-of-text.html">Images of Text (1.4.5, Level AA)</a></li>
<li><a href="https://www.w3.org/WAI/WCAG21/Understanding/visual-presentation.html">Visual Presentation (1.4.8, Level AAA)</a></li>
<li><a href="https://www.w3.org/WAI/WCAG21/Understanding/images-of-text-no-exception.html">Images of Text - No Exception (1.4.9, Level AAA)</a></li>
<li><a href="https://www.w3.org/WAI/WCAG21/Understanding/reflow.html">Reflow (1.4.10, Level AA)</a></li>
<li><a href="https://www.w3.org/WAI/WCAG21/Understanding/non-text-contrast.html">Non-text Contrast (1.4.11, Level AA)</a></li>
<li><a href="https://www.w3.org/WAI/WCAG21/Understanding/text-spacing.html">Text Spacing (1.4.12, Level AA)</a></li>
</ul>
<p>No guarantees on those "bonus" criteria. But they are worth learning and exploring how to apply in the context of your page and website.</p>
<p>Go, you!</p>
<h2 data-sanitized-id="when-tables-get-complicated">When tables get complicated</h2>
<p>Sometimes you don't want to reach for <code>table</code> because it's complicated, for one reason or another:</p>
<ul>
<li>You were given a graphic of a table, rather than text content, and don't have an easy way to make it real text, despite the existence of <a href="https://www.lireo.com/extracttable/">ExtractTable, which converts data from images</a>.</li>
<li>You're using a framework like Rails or a CMS like WordPress that generates HTML, and you can't edit it or it's difficult to edit.</li>
<li>You struggle with CSS.</li>
<li>The default design is ugly and doesn't "fit" into your site's design.</li>
</ul>
<p>Maybe at this point, you've gotten past those issues, and you're really trying. But sometimes tables are just... hard. You've been asked to put form inputs in there. Your table needs to be dynamically sortable. Or you have loads of information, but it barely fits on a large viewport, and horizontally overflows on a small viewport.</p>
<p>It's OK to get frustrated. We've all encountered challenges when given a complex design idea. And some solutions are imperfect.</p>
<p>What I'm sharing in this article is meant to lead you in the right direction. Categorizing and building things is hard in real life.</p>
<p>You could learn from Adrian Roselli, who has tackled some of the hard issues:</p>
<ul>
<li><a href="https://adrianroselli.com/2020/02/block-links-cards-clickable-regions-etc.html#Update02">Block Link, Cards, Clickable Regions, Row, Etc. - March 31, 2020 update</a></li>
<li><a href="https://adrianroselli.com/2019/05/uniquely-labeling-fields-in-a-table.html">Uniquely Labeling Fields in a Table</a></li>
<li><a href="https://adrianroselli.com/2022/01/accessible-cart-tables.html">Accessible Cart Tables?</a></li>
<li><a href="https://adrianroselli.com/2019/09/table-with-expando-rows.html">Table with Expando Rows</a></li>
<li><a href="https://adrianroselli.com/2018/02/tables-css-display-properties-and-aria.html">Tables, CSS Display Properties, and ARIA</a></li>
<li><a href="https://adrianroselli.com/2020/11/under-engineered-responsive-tables.html">Under-Engineered Responsive Tables</a></li>
<li><a href="https://adrianroselli.com/2022/07/its-mid-2022-and-browsers-mostly-safari-still-break-accessibility-via-display-properties.html">It’s Mid-2022 and Browsers (Mostly Safari) Still Break Accessibility via Display Properties</a></li>
</ul>
<p>And there are others to learn from, too:</p>
<ul>
<li><a href="https://www.matuzo.at/blog/highlighting-columns/#table1-occurrences?ref=bestwebsite.gallery">Highlighting columns in HTML tables by Manuel Matuzovic</a></li>
<li><a href="https://www.scottohara.me/blog/2019/04/19/tabled-tables.html">Unintentionally tabling table semantics by Scott O'Hara</a></li>
<li><a href="https://inclusive-components.design/data-tables/">Data tables by Heydon Pickering</a></li>
</ul>
<h3 data-sanitized-id="other-things-to-beware">Other things to beware</h3>
<p>You've done your research, you've created solutions, but sometimes you still run into problems. Keep these things in mind:</p>
<ul>
<li>Nested tables can break a screen reader user's experience. Try rearranging your table, or make multiple tables to keep them simple.</li>
<li>Tables with lots of columns are hard to wrangle for the different screen sizes out there. There is no perfect solution. Experiment with ways to help the data reflow and stack without losing its context and relationships.</li>
<li>Changing the CSS <code>display</code> value on the <code>table</code> element breaks the semantics of the table  and breaks a screen reader user's experience.</li>
<li>In Safari 16, VoiceOver for Mac will read a <code>caption</code> as the table's name, but will not see a nested heading level in:
<ul>
<li>the Web Rotor headings list, and</li>
<li>the "next heading" keyboard shortcut.</li>
</ul>
</li>
<li>HTML generators and Markdown commonly exclude some table elements and attributes, like caption and scope.</li>
</ul>
<h2 data-sanitized-id="go-forth-and-make-good-tables">Go forth, and make good tables</h2>
<p>Whew! I feel like I could jabber on and on about the importance of table markup.</p>
<p>However, here are the main things I want you to remember :</p>
<ul>
<li>Don't use <code>table</code> for layouts.</li>
<li>Avoid nesting tables and simplify data relationships, where possible.</li>
<li>Ensure each table has an accessible name, whether it be:
<ul>
<li><code>table &gt; caption</code></li>
<li><code>table aria-label={Table name}</code></li>
<li><code>figure &gt; figcaption + table</code>;</li>
<li><code>h{#} id={table-name}</code> + <code>table aria-labelledby={heading id}</code> (use with caution).</li>
</ul>
</li>
<li>This shouldn't have to be said, but don't ARIA overload a table.</li>
<li>Test your work with a screen reader or, even better, a proficient screen reader user.</li>
<li>Take a deep breath and try not to overthink it.</li>
</ul>
<p>I urge you in the coming year, use real tables for tabular data!</p>
<h2 data-sanitized-id="learn-html-(including-tables)-for-free">Learn HTML (including tables) for free</h2>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/HTML_basics">HTML basics on MDN</a></li>
<li><a href="https://www.30daysofhtml.com/">30 Days of HTML by Jen Kramer</a></li>
<li><a href="https://www.w3.org/WAI/tutorials/tables/">Tables Tutorial by W3C-WAI</a></li>
<li><a href="https://webaim.org/techniques/tables/">WebAIM's Creating Accessible Tables</a></li>
<li><a href="https://www.w3.org/WAI/WCAG21/quickref/?currentsidebar=%23col_customize&amp;tags=tables">How to Meet WCAG Quick Reference: tables tag filter</a></li>
<li><a href="https://websitesetup.org/html-tutorial-beginners/">Beginner's Guide to Writing Good HTML by Bruce Lawson</a></li>
<li><a href="https://thegymnasium.com/courses/GYM/107/0/about">Modern Web Design by Aaron Gustafson (sign-up with Aquent Gymnasium)</a></li>
<li><a href="https://web.dev/learn/html/">Learn HTML by Estelle Weyl</a></li>
</ul>
<h2 data-sanitized-id="testing-tools">Testing tools</h2>
<ul>
<li><a href="https://pauljadam.com/bookmarklets/tables.html">Paul J. Adam's Tables Bookmarklet for Accessibility Testing</a></li>
<li><a href="https://wave.webaim.org/">WebAIM's WAVE tool</a></li>
</ul>
<h2 data-sanitized-id="special-thanks">Special thanks</h2>
<p>This write-up wouldn't be possible without the generous time and critical review from my friends and accessibility allies:</p>
<ul>
<li><a href="https://www.lireo.com/">Deborah Edwards-Oñoro</a></li>
<li><a href="https://incl.ca/">Nic Steenhout</a></li>
<li><a href="https://adrianroselli.com/">Adrian Roselli</a></li>
<li><a href="https://www.matuzo.at/">Manuel Matuzovic</a></li>
</ul>


guid: https://htmhell.dev/adventcalendar/2022/15/
title: Get that marquee ✨AeStHeTiC✨
author: ;Manuel Matuzovic
link: https://htmhell.dev/adventcalendar/2022/15/
hash: ��AP.�h�G�
attributes: {"enclosures":[]}
content:
<p>With the current <a href="https://www.urbandictionary.com/define.php?term=Y2K%20aesthetic">Y2K fashion trend</a> and JLo being back together with Ben Affleck, the 2000s are having a revival this year. Many brands are jumping onto the boat by creating websites with an “old-school” vibe.</p>
<p>
<img src="https://htmhell.dev/images/advent2022/14/sepronic_world.jpg" alt="SEPRONIC WORLD by Thea Wood on Behance" width="740" height="246">
</p>
<p><a href="https://www.behance.net/gallery/116549859/SEPRONIC-WORLD?tracking_source=search_projects_recommended%7Cwindowsxp"><em>SEPRONIC WORLD by Thea Wood on Behance</em></a></p>
<p>The <code>marquee</code> element is an old web dev community favourite, fitting the 2000s aesthetic. However, this HTML element is deprecated and should not be used on modern websites. If you still want to achieve that unique <code>marquee</code> aesthetic, this article is here to help. First, we learn about the history of the marquee element and look at the pros and cons. Then <a href="https://htmhell.dev/adventcalendar/2022/15/#the-alternative">we code an alternative</a> with CSS and JavaScript.</p>
<h2 data-sanitized-id="the-marquee-element">The Marquee element</h2>
<p>The <code>marquee</code> element has never been a standard HTML element and is even classified as a non-conforming feature in HTML5. This means it is entirely obsolete and must not be used, according to the <a href="https://www.w3.org/Consortium/">World Wide Web Consortium (W3C)</a>. Microsoft introduced the <code>marquee</code> element in Internet Explorer version 2.0, which was launched in 1995. Since then, it was quickly integrated into other browsers, although it never made it to the HTML specification.</p>
<h3 data-sanitized-id="but-what-does-it-do?">But what does it do?</h3>
<p>When text or an image is placed inside a <code>marquee</code> element, it moves across the page infinitely, per default horizontally, from right to left.</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;!-- This scrolling text goes from right to left --&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>marquee</span><span data-sanitized-class="token punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  Newsflash: JLo and Ben Affleck got married!</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>marquee</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<div data-demo="Demo of a standard marquee">
  NEWSFLASH: JLo and Ben Affleck got married!
</div>
<p>With the help of attributes, the content within the element can also scroll right, up or down. You can even control what happens when the corner of the screen is reached, how fast the animation is or if it has is a delay.</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;!-- Using an attribute to change the scroll direction --&gt;</span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token comment">&lt;!-- This scrolling text goes from top to bottom. The "scrollamount" attribute controls the speed. --&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>marquee</span> <span data-sanitized-class="token attr-name">direction</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>down<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">scrollamount</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 punctuation">&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  Be prepared for low-rise jeans, Y2K is back.</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>marquee</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<div data-demo="Demo of a marquee scrolling top to bottom">
  Be prepared for low-rise jeans, Y2K is back.
</div>
<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;!-- Using an attribute to change the scroll behaviour --&gt;</span></span><br><span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>marquee</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token attr-name">direction</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>up<span data-sanitized-class="token punctuation">"</span></span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token attr-name">behavior</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>alternate<span data-sanitized-class="token punctuation">"</span></span></span><br><span data-sanitized-class="highlight-line">  <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>250<span data-sanitized-class="token punctuation">"</span></span></span><br><span data-sanitized-class="highlight-line">  <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>200<span data-sanitized-class="token punctuation">"</span></span></span><br>  <span data-sanitized-class="token special-attr"><span data-sanitized-class="token attr-name">style</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 value css language-css"><span data-sanitized-class="token property">border</span><span data-sanitized-class="token punctuation">:</span>solid</span><span data-sanitized-class="token punctuation">"</span></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>marquee</span> <span data-sanitized-class="token attr-name">behavior</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>alternate<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 comment">&lt;!-- This image bounces from the edges of the screen --&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>img</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>40<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>https://www.freeiconspng.com/uploads/dvd-logo-png-33.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 data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;/</span>marquee</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>marquee</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<div data-demo="Demo of a marquee with a picture and different scroll behavior">

  
    
    <img width="85" src="https://htmhell.dev/images/advent2022/14/dvd-logo-png-19280.png">
  

</div>
<h3 data-sanitized-id="the-popularity-of-marquee">The popularity of <code>marquee</code></h3>
<p>Although the marquee element was never accepted as a standard, people loved using it on their websites. It could be easily implemented and offered a bit of fun, way before CSS animations were a thing. <code>Marquee</code> was often used for under-construction pages or websites with headlines. Text or images moving across the screen served as a successful attention grabber.</p>
<p>You may be asking yourself why the <code>marquee</code> element gets a wave of attention now, in 2022. As the Y2K trend has a revival within fashion, brands also want to bring retro vibes and aesthetics to their websites. What better markets ultra-low-rise jeans than a website with blinking, colourful images and moving text? Well, you probably have guessed it: a website that uses modern user experience and accessibility practices to be enjoyable for everyone. Moving content grabs your attention, but it is also very distracting. Surfing the web should be a pleasant experience for every individual.</p>
<h3 data-sanitized-id="some-reasons-against-marquee">Some reasons against <code>marquee</code></h3>
<p>Although moving text at high speed over a screen may sound compelling to try out the <code>marquee</code> element in your next web project, you really shouldn't. Here are some reasons for you if you are not convinced yet:</p>
<h4>1. Officially deprecated</h4>
<p>The usage of the <code>marquee</code> element is no longer recommended. It is officially marked as deprecated, meaning modern browsers might still support it for compatibility purposes. However, the element could be removed anytime, and newer or better alternatives are available. So, it should definitely not be used anymore.</p>
<h4>2. Not accessible</h4>
<p>The <code>marquee</code> element was launched without ever being tested properly, specifically regarding accessibility. This resulted in issues for people with visual impairments and cognitive disabilities. In addition, the element doesn't clearly define what its content is. It can be just text, an image, a link or something else. When assistive devices like screen readers don't know how to announce a website's content, their users might miss it or don't understand its purpose.</p>
<p>Automatically scrolling text can be unreadable by some people and severely distracting. Especially users with attention deficits have a hard time concentrating on other parts of the website when some content is moving or blinking. Some users also experience nausea from animated content. Such content can also cause problems for people using assistive technology to surf the web. These problems occur regardless of scrolling speed.</p>
<p>The latest version of the <a href="https://www.w3.org/TR/WCAG22/">Web Content Accessibility Guidelines (WCAG 2.2)</a> clearly presents recommendations to avoid the distraction of users during their interaction with a website. The <a href="https://www.w3.org/TR/WCAG22/#pause-stop-hide">success criterion 2.2.2</a> states that moving, blinking and scrolling information needs a mechanism to be paused or stopped. This rule applies if the animation:</p>
<ol>
<li>starts automatically</li>
<li>lasts longer than five seconds</li>
<li>is presented parallel with other content</li>
</ol>
<p>This requirement is Level A, meaning it is the minimum level of accessibility. Many users with disabilities will find it very difficult or impossible to access information. All websites should at least satisfy the minimum accessibility criteria.</p>
<h4>3. Usability problems</h4>
<p>The human eye is attracted to movement. As the content within the <code>marquee</code> element is constantly moving, it can be distracting for anybody, not just people with disabilities. Therefore using the marquee element results not only in accessibility but also in usability problems on a website.</p>
<p>When text inside a <code>marquee</code> element contains a link, additional problems occur. Clicking on a moving link is more complicated than clicking on static text. Depending on the speed and length of the scrolling text, some users may be unable to do so.</p>
<p>Users can also have difficulties printing a website if its content is not always fully visible. When multiple attempts are needed to complete the printing task, it makes it very inefficient, if not impossible.</p>
<h2 data-sanitized-id="the-alternative">The Alternative</h2>
<p>If you still want to get the "marquee aesthetic", there is a way without using the element. CSS <a href="https://drafts.csswg.org/css-animations/">animations</a> are a more suitable method. Creating the scrolling effect with CSS needs a bit more code to implement than using a single line of HTML. However, CSS is still the recommended practice as it is used to style content and create presentational effects, whereas HTML is not. In addition, CSS can be used to create more powerful and advanced animations. So let's get right into it.</p>
<h3 data-sanitized-id="replacing-the-marquee-element">Replacing the <code>marquee</code> element</h3>
<p>As a first step, we choose a standard HTML element instead of the <code>marquee</code> element. Depending on the type of content we want to animate, a different HTML element will be appropriate.</p>
<p>For the first example, we want to animate text. Therefore, we use the <code>p</code> element. We wrap this element inside a <code>div</code> container and add a class called <code>marquee-alternative</code>. This class name is arbitrary and was just added to style and animate our fake marquee with CSS later.</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>marquee-alternative<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>Newsflash: JLo and Ben Affleck got married!<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>div</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<h3 data-sanitized-id="styling-the-fake-marquee-element">Styling the fake marquee element</h3>
<p>The classic HTML <code>marquee</code> element typically moves across the screen's whole width. To recreate this original effect for our fake marquee element, we first set the <code>overflow</code> to <code>hidden</code> on the <code>div</code> container, which has the class <code>marquee-alternative</code>. This makes sure that no unwanted vertical scrolling is possible. We also assure the container has a <code>width</code> of <code>100%</code>.</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">.marquee-alternative</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">overflow</span><span data-sanitized-class="token punctuation">:</span> hidden<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">width</span><span data-sanitized-class="token punctuation">:</span> 100%<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>The <code>p</code> element inside the <code>marquee-alternative</code> container needs some basic styling as well. To remove all unwanted default spacing of the <code>p</code> element, we set the <code>margin</code> to <code>0</code>. We also set the <code>width</code> to <code>fit-content</code>. This assures that the <code>p</code> element has the length of its content. This is important as we want the text of our fake marquee element to loop through without any delay. If the <code>p</code> element had the whole width of the screen (100%), there would be a few seconds where our marquee text is not visible after it left the screen.</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">.right-to-left p</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">margin</span><span data-sanitized-class="token punctuation">:</span> 0<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">width</span><span data-sanitized-class="token punctuation">:</span> fit-content<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>
<h3 data-sanitized-id="adding-movement-with-css">Adding movement with CSS</h3>
<p>We can use CSS animations to move our fake marquee element over the screen. To create an animation, we use the<code>@keyframes</code> directive. Our custom animation called <code>marquee-right-to-left</code> starts at <code>100vw</code> (far right) and ends at <code>-100%</code> (far left). This means that our fake marquee begins outside the screen on the right side and moves to the left, ending outside the screen as well.</p>
<pre data-sanitized-class="language-css"><code data-sanitized-class="language-css"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token atrule"><span data-sanitized-class="token rule">@keyframes</span> marquee-right-to-left</span><span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token selector">from</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token property">transform</span><span data-sanitized-class="token punctuation">:</span> <span data-sanitized-class="token function">translateX</span><span data-sanitized-class="token punctuation">(</span>100vw<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 selector">to</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token property">transform</span><span data-sanitized-class="token punctuation">:</span> <span data-sanitized-class="token function">translateX</span><span data-sanitized-class="token punctuation">(</span>-100%<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></code></pre>
<p>You may wonder why we use <code>100vw</code> as the start value and not <code>100%</code>. This is because we previously set the width of the <code>p</code> element to fit its content. If we used <code>100%</code> as a start value, the animation would not start outside of the screen but somewhere else, depending on the content length.</p>
<p><strong>Note:</strong> If you implement your fake marquee element and it is not supposed to move across the whole screen width, you must adapt the <code>100vw</code> value to your use case.</p>
<p>To start our keyframe animation, we add some animation properties to our <code>p</code> element. We refer to our <code>marquee-right-to-left</code> keyframe by setting the <code>animation-name</code>. We also specify an <code>animation-duration</code> of 20 seconds, <code>linear</code> movement and <code>infinite</code> repetitions. Depending on your desired marquee aesthetic, you can adapt these values to change the animation style according to your needs.</p>
<p>The shortened version of adding our CSS animation would be <code>animation: marquee-right-to-left 20s linear infinite;</code> instead of writing the 4 separate properties.</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">.marquee-alternative p</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">margin</span><span data-sanitized-class="token punctuation">:</span> 0<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">width</span><span data-sanitized-class="token punctuation">:</span> fit-content<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">animation-name</span><span data-sanitized-class="token punctuation">:</span> marquee-right-to-left<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">animation-duration</span><span data-sanitized-class="token punctuation">:</span> 20s<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">animation-iteration-count</span><span data-sanitized-class="token punctuation">:</span> infinite<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">animation-timing-function</span><span data-sanitized-class="token punctuation">:</span> linear<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>
<div data-demo="Demo of our fake marquee">
  <div data-sanitized-class="advent2022 marquee-alternative">
    <p>Newsflash: JLo and Ben Affleck got married!</p>
  </div>
</div>
<p>Now our fake marquee element should work, just like the old HTML classic. <strong>But wait, we are not finished yet!</strong></p>
<h3 data-sanitized-id="dont-forget-accessibility">Don’t forget accessibility</h3>
<p>Some measures can be taken to make our fake marquee element more accessible and user-friendly.</p>
<h4>Reduce motion</h4>
<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion"><code>prefers-reduced-motion</code> media query</a> can be used to stop all animations for users that don't want them. As it is hard to decide when an animation is slow enough for people with disabilities, the best practice is to pause them entirely. In our case, we use the <code>prefers-reduced-motion</code> media query to only enable the animation if a user has no other preferences set.</p>
<p>We remove the <code>animation</code> property from the <code>.marquee-alternative p</code> nested class above and wrap it inside the media query.</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">.marquee-alternative p</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">margin</span><span data-sanitized-class="token punctuation">:</span> 0<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">width</span><span data-sanitized-class="token punctuation">:</span> fit-content<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token comment">/* animation got removed here */</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><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token comment">/* Only shows animation for users that have set no motion preference */</span></span><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token atrule"><span data-sanitized-class="token rule">@media</span> <span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token property">prefers-reduced-motion</span><span data-sanitized-class="token punctuation">:</span> no-preference<span data-sanitized-class="token punctuation">)</span></span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token comment">/* animation is added here */</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token selector">.marquee-alternative p</span><span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token property">animation</span><span data-sanitized-class="token punctuation">:</span> marquee-right-to-left 20s linear infinite<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></code></pre>
<h4>Pause the animation</h4>
<p>There are two different ways to pause the <code>marquee</code> animation. We can add a pause/play <code>button</code> or stop the animation on <code>hover</code>. Adding a <code>button</code> would be a cleaner and more accessible option. However, some projects may not allow adding an extra <code>button</code>.  That is when we use the <code>hover</code> alternative with the help of a media query.</p>
<h5>Pause the animation on hover and on focus</h5>
<p>To ease the reading act and fight the issue of chasing moving text, we pause the animation when a user hovers over the marquee container (the <code>div</code>) or sets the focus on it. This is done by setting the <code>animation-play-state</code> to <code>paused</code> for the <code>p</code> element, on <code>hover</code> and <code>focus</code> of the <code>div</code>.</p>
<pre data-sanitized-class="language-css"><code data-sanitized-class="language-css"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token comment">/* Pause animation on hover and on focus */</span></span><br><span data-sanitized-class="token selector">.marquee-alternative:hover p,<br>.marquee-alternative:focus p</span><span data-sanitized-class="token punctuation">{</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">animation-play-state</span><span data-sanitized-class="token punctuation">:</span> paused<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>
<div data-demo="Demo of our fake marquee that pauses on hover and focus">
<div tabindex="0" data-sanitized-class="advent2022 marquee-alternative-2">
  <p>Newsflash: JLo and Ben Affleck got married!</p>
</div>
</div>
<h5>Add a pause/play button</h5>
<p>To comply with the previously named WCAG criterion 2.2.2, we add a play and pause button for the animation. Not every user has set their motion preferences to <code>reduce</code>. We still want to allow everybody to pause the animation if it is perceived as too distracting.</p>
<p><strong>Note:</strong> When you implement the pause/play button, remove the <code>animation-play-state: pause</code> from the previous step. Otherwise, it would confuse users why the text is paused although they haven't pressed the button yet.</p>
<p>As a first step, we wrap our existing <code>marquee-alternative</code> container into another <code>div</code> and assign it the class <code>marquee-container</code>. We then add a <code>button</code> element to start and stop the animation. It has the class <code>btn</code> and the <code>aria-pressed</code> state set to <code>false</code>. The <code>p</code> element gets the class <code>marquee-content</code> assigned to it. We also add the <code>animation-play-state</code> style to the <code>p</code> element to be able to change it later on with JavaScript.</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>marquee-container<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>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>marquee-alternative<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 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>marquee-content<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token special-attr"><span data-sanitized-class="token attr-name">style</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 value css language-css"><span data-sanitized-class="token property">animation-play-state</span><span data-sanitized-class="token punctuation">:</span> running<span data-sanitized-class="token punctuation">;</span></span><span data-sanitized-class="token punctuation">"</span></span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Newsflash: JLo and Ben Affleck got married!<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>div</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 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>button<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>btn<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">aria-pressed</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 punctuation">&gt;</span></span>Pause<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>div</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>Now we add a little bit of styling to the new HTML elements. This CSS code is added in addition to the already existing styling from before.</p>
<p>The <code>.marquee-container</code> gets a <code>border</code> and <code>flex</code> position. All elements inside the container are aligned in its centre. The <code>.marquee-content</code>, which is our text, gets some styling as well.</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">.marquee-container</span> <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> flex<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">align-items</span><span data-sanitized-class="token punctuation">:</span> center<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">border</span><span data-sanitized-class="token punctuation">:</span> 3px solid #000<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><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token selector">.marquee-content</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">margin</span><span data-sanitized-class="token punctuation">:</span> 0<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">width</span><span data-sanitized-class="token punctuation">:</span> fit-content<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>The <code>button</code> gets a basic styling by changing the <code>background-color</code>, <code>border</code>, <code>box-shadow</code>, <code>cursor</code> and <code>padding</code>. Make sure to add enough <code>padding</code> that the <code>button</code> has a minimum size of 48x48 px. This is the minimum click area a <code>button</code> should have to be accessible. <code>Hover</code> and <code>focus</code> styles are added to have a more apparent visual change when interacting with the button. We also change the visual appearance of the <code>button</code> when it gets pressed by styling it when <code>aria-pressed</code> is set to <code>true</code>.</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">.btn</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">cursor</span><span data-sanitized-class="token punctuation">:</span> pointer<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">background-color</span><span data-sanitized-class="token punctuation">:</span> #fff<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">border</span><span data-sanitized-class="token punctuation">:</span> 0<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">border-left</span><span data-sanitized-class="token punctuation">:</span> 3px solid #000<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">padding</span><span data-sanitized-class="token punctuation">:</span> 1.1rem 1rem<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">box-shadow</span><span data-sanitized-class="token punctuation">:</span> 0 0.5rem 0.5rem -0.125rem #0005<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><br><span data-sanitized-class="token selector">.btn:hover,<br><span data-sanitized-class="highlight-line">.btn:focus-visible,</span><br>.btn[aria-pressed="true"]:hover</span> <span data-sanitized-class="token punctuation">{</span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">color</span><span data-sanitized-class="token punctuation">:</span> #fff<span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">background-color</span><span data-sanitized-class="token punctuation">:</span> #000<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><br><span data-sanitized-class="highlight-line"><span data-sanitized-class="token selector">.btn[aria-pressed="true"]</span> <span data-sanitized-class="token punctuation">{</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token property">box-shadow</span><span data-sanitized-class="token punctuation">:</span> 0 0.5rem 0.5rem -0.125rem inset #0005<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>For the JavaScript part of this implementation, we first query the <code>marquee-content</code> (<code>p</code> element) and the <code>button</code> with the help of <code>document.querySelector</code> and save them into variables. This is done to make the code more readable.</p>
<pre data-sanitized-class="language-jsx"><code data-sanitized-class="language-jsx"><span data-sanitized-class="highlight-line"><span data-sanitized-class="token keyword">let</span> marqueeText <span data-sanitized-class="token operator">=</span> document<span data-sanitized-class="token punctuation">.</span><span data-sanitized-class="token function">querySelector</span><span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token string">".marquee-content"</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> button <span data-sanitized-class="token operator">=</span> document<span data-sanitized-class="token punctuation">.</span><span data-sanitized-class="token function">querySelector</span><span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token string">".btn"</span><span data-sanitized-class="token punctuation">)</span><span data-sanitized-class="token punctuation">;</span></span></code></pre>
<p>We then add an event listener for the <code>click</code> event of the <code>button</code>. When the <code>button</code> is clicked, we check if the animation is currently running by looking at the <code>animationPlayState</code>. If it is <code>running</code>, we stop the animation by setting the state to <code>paused</code>. We also change the <code>button.innerText</code> and set <code>ariaPressed</code> to <code>true</code>. As the <code>button</code> serves as a pause and play button, we also add the functionality of enabling the animation again after it was stopped. This is done by setting the <code>animationPlayState</code> back to <code>running</code> and changing the <code>button.innerText</code> and <code>ariaPressed</code> state again.</p>
<pre data-sanitized-class="language-jsx"><code data-sanitized-class="language-jsx"><span data-sanitized-class="highlight-line">button<span data-sanitized-class="token punctuation">.</span><span data-sanitized-class="token function">addEventListener</span><span data-sanitized-class="token punctuation">(</span><span data-sanitized-class="token string">"click"</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 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> isRunning <span data-sanitized-class="token operator">=</span> marqueeText<span data-sanitized-class="token punctuation">.</span>style<span data-sanitized-class="token punctuation">.</span>animationPlayState <span data-sanitized-class="token operator">==</span> <span data-sanitized-class="token string">"running"</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 comment">// change behaviour of animation and button</span></span><br><span data-sanitized-class="highlight-line">  <span data-sanitized-class="token keyword">if</span> <span data-sanitized-class="token punctuation">(</span>isRunning<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">// stop the animation</span></span><br><span data-sanitized-class="highlight-line">    marqueeText<span data-sanitized-class="token punctuation">.</span>style<span data-sanitized-class="token punctuation">.</span>animationPlayState <span data-sanitized-class="token operator">=</span> <span data-sanitized-class="token string">"paused"</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token comment">// change button text</span></span><br><span data-sanitized-class="highlight-line">    button<span data-sanitized-class="token punctuation">.</span>innerText <span data-sanitized-class="token operator">=</span> <span data-sanitized-class="token string">"Play"</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">    button<span data-sanitized-class="token punctuation">.</span>ariaPressed <span data-sanitized-class="token operator">=</span> <span data-sanitized-class="token string">"true"</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 comment">// start the animation</span></span><br><span data-sanitized-class="highlight-line">    marqueeText<span data-sanitized-class="token punctuation">.</span>style<span data-sanitized-class="token punctuation">.</span>animationPlayState <span data-sanitized-class="token operator">=</span> <span data-sanitized-class="token string">"running"</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">    <span data-sanitized-class="token comment">// change button text</span></span><br><span data-sanitized-class="highlight-line">    button<span data-sanitized-class="token punctuation">.</span>innerText <span data-sanitized-class="token operator">=</span> <span data-sanitized-class="token string">"Pause"</span><span data-sanitized-class="token punctuation">;</span></span><br><span data-sanitized-class="highlight-line">    button<span data-sanitized-class="token punctuation">.</span>ariaPressed <span data-sanitized-class="token operator">=</span> <span data-sanitized-class="token string">"false"</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></code></pre>
<div data-demo="Demo of our fake marquee with a pause and play button">
<div data-sanitized-class="advent2022 marquee-container-3">
  <div data-sanitized-class="marquee-alternative-3">
    <p data-sanitized-class="marquee-content-3">Newsflash: JLo and Ben Affleck got married!</p>
  </div>
  <button type="button" aria-pressed="false" data-sanitized-class="btn-marquee">Pause</button>
</div>
</div>
<p>Your fake marquee element can now be stopped and activated again with the click of a button. This allows users to decide for themselves if they want to see the scrolling content on the screen or not.</p>
<h2 data-sanitized-id="conclusion">Conclusion</h2>
<p>Using the marquee aesthetic is a fun way of animating web content and grabbing a user's attention. But please be aware of the <code>marquee</code> element's impact on people. Even if the desired retro aesthetic is achieved without using the actual element but the presented alternative, the same named usability and accessibility concerns remain. So if you implement scrolling, animated content on your website, be conscious of its downsides and take measures to make the experience more accessible.</p>


guid: https://odysee.com/interview-a-talk-with-eva-karene:78e10580a10a08eda46352e855a8e1bb88dcfcf8
title: Interview: "A talk with Eva Karene Bartlett"
author: ;Eva K Bartlett
link: https://odysee.com/interview-a-talk-with-eva-karene:78e10580a10a08eda46352e855a8e1bb88dcfcf8
hash: ���l�PS��Τ� ^
content:
<p><img src="https://thumbnails.lbry.com/sKpw90HMnlw" width="480" alt="thumbnail" title="Interview: " a talk with eva karene bartlett></p>Interview I did yesterday. Absolutely lovely man--Alexandre Guerreiro--who interviewed me, he brought knowledge &amp; compassion to the interview.<br><br>First published here:<br>https://www.youtube.com/watch?v=1BeXKYSO5HY<br><br>His Twitter: <br>https://twitter.com/ATGuerreiro<br>...<br>https://www.youtube.com/watch?v=sKpw90HMnlw

attributes:
{"enclosures":[{"url":"https://player.odycdn.com/api/v3/streams/free/interview-a-talk-with-eva-karene/78e10580a10a08eda46352e855a8e1bb88dcfcf8/8847d5.mp4","type":"video/mp4","length":374401373}]}


guid: https://christitus.com/cleanup-docker/
title: Cleanup Docker
link: https://christitus.com/cleanup-docker/
hash: ��/����\Kꇼ#L�
attributes: {"enclosures":[]}
content:
<p>If you are running docker you will accumulate a lot of unused images and volumes as you update running containers. This makes maintenance a necessity.</p>
<blockquote data-sanitized-class="twitter-tweet"><p lang="en" dir="ltr">Running Docker? Be sure and cleanup unused images and volumes with:<br>docker volume rm $(docker volume ls -f dangling=true -q)<br>docker rmi $(docker images --quiet --filter "dangling=true")</p>— Chris Titus Tech (@christitustech) <a href="https://twitter.com/christitustech/status/1603766983274729472?ref_src=twsrc%5Etfw">December 16, 2022</a></blockquote>

<h2 data-sanitized-id="do-you-need-this">Do you need this?</h2>
<p>Check your portainer status page and look for “unused” images and containers. If you are seeing a lot of these, then you are wasting space and I’d recommend running this script to clean them up!</p>
<h2 data-sanitized-id="the-cleanup-script">The Cleanup Script</h2>
<p>Run this bash script every week to ensure the cleanup gets performed.</p>
<div data-sanitized-class="highlight"><pre tabindex="0" data-sanitized-class="chroma"><code data-lang="bash" data-sanitized-class="language-bash"><span data-sanitized-class="line"><span data-sanitized-class="cl"><span data-sanitized-class="cp">#!/bin/bash
</span></span></span><span data-sanitized-class="line"><span data-sanitized-class="cl"><span data-sanitized-class="cp"></span>
</span></span><span data-sanitized-class="line"><span data-sanitized-class="cl">docker volume rm <span data-sanitized-class="k">$(</span>docker volume ls -f <span data-sanitized-class="nv">dangling</span><span data-sanitized-class="o">=</span><span data-sanitized-class="nb">true</span> -q<span data-sanitized-class="k">)</span>
</span></span><span data-sanitized-class="line"><span data-sanitized-class="cl">docker rmi <span data-sanitized-class="k">$(</span>docker images --quiet --filter <span data-sanitized-class="s2">"dangling=true"</span><span data-sanitized-class="k">)</span>
</span></span></code></pre></div>


guid: https://christitus.com/acronis-true-image/
title: Acronis Cyber Protect Home Office
link: https://christitus.com/acronis-true-image/
hash: �$rO&t�I`)u�P
attributes: {"enclosures":[]}
content:
<p>Acronis True Image has undergone an expansion and rename in the past couple years to Acronis Cyber Protect Home Office. This is a quick breakdown of their new offering.</p>
<h2 data-sanitized-id="backup">Backup</h2>
<p><img loading="lazy" src="https://christitus.com/images/2022/acronis-true-image/backup.webp" alt="" data-sanitized-class="img-fluid"> </p>
<p>Acronis backup is what the company is known for as it offered block level backup over 10 years ago. Their backup services have always been some of the best and this still holds true today. The interface is simplified and intuitive. It can get a complete copy of the entire system while its online and back it up locally or to the cloud.</p>
<p>Transfer rates to the cloud on my connection maxed out around 95 Mbps and went as low as 50 Mbps. This is average for most cloud backup speeds in the residential realm.</p>
<h2 data-sanitized-id="anti-virus">Anti-Virus</h2>
<p><img loading="lazy" src="https://christitus.com/images/2022/acronis-true-image/av.webp" alt="" data-sanitized-class="img-fluid"> </p>
<p>One of the biggest additions is the inclusion of anti-virus. This protection is adequate and it brings the entire protection suite in-house. I’m not a fan of most AV implementations and what matters is a good backup when these inevitably fail. It makes sense that they included this, but to me it makes the software seem bloated and unnecessary.</p>
<h2 data-sanitized-id="file-sync">File Sync</h2>
<p><img loading="lazy" src="https://christitus.com/images/2022/acronis-true-image/sync.webp" alt="" data-sanitized-class="img-fluid"> </p>
<p>This addition is beneficial for those with space concerns or multiple computers. The archive feature removes the file from the local device once it uploads it to the Acronis online cloud. The sync function is like Dropbox and syncs files across devices.</p>
<h2 data-sanitized-id="other-tools">Other Tools</h2>
<p>Disk Clone - is helpful when replacing hard drives. I used to use this all the time when SDDs hit the market and I was replacing legacy hard drives.</p>
<p>It uses 84 FOSS programs listed on their website: <a href="https://kb.acronis.com/content/69667">https://kb.acronis.com/content/69667</a></p>
<h2 data-sanitized-id="cost">Cost</h2>
<p><img loading="lazy" src="https://christitus.com/images/2022/acronis-true-image/cost.webp" alt="" data-sanitized-class="img-fluid"> </p>
<p>The product has moved to a subscription model. The essential model is local and offers the core backup services with no cloud. The advanced function could work for those that don’t need a full image of their device, but to utilise the software to its fullest capacity it will cost you $124.99 per year for the software with 1 TB of storage. Each additional TB of storage adds $40. No doubt this is on the high end of cost when compared to the competition and why they added they expanded its offerings past backup to help justify the price.</p>
<h2 data-sanitized-id="walkthrough-video">Walkthrough Video</h2>
<div>
<iframe allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/VYTCeIHS6Kg?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" title="YouTube video" sandbox="allow-scripts allow-same-origin"></iframe>
</div>


guid: https://htmhell.dev/adventcalendar/2022/16/
title: 5 HTML elements, And a partridge in a despair tree
author: ;Manuel Matuzovic
link: https://htmhell.dev/adventcalendar/2022/16/
hash: ���?��?P�ئ����
attributes: {"enclosures":[]}
content:
<p>HTML is a beautiful programming language. It comes with many out-of-the-box accessibility benefits—it conveys semantic meaning to assistive technology, enabling people to consume content and complete often important journeys that they may not be able to do outside of the web. So why is all that goodness we can get for free ignored so often?</p>
<p>To expand on that point a little, why do we ignore native HTML elements that will tell people exactly what their purpose is and enable them to interact with it, and use overly complex ARIA-laden JavaScript solutions? Some of this may come down to how something is designed, while in other cases it may be misunderstanding/confusion or copied-and-pasted bad practices. In this article, we'll look at 5 common instances when semantic HTML is ignored.</p>
<h2 data-sanitized-id="lessbuttongreater"><code>&lt;button&gt;</code></h2>
<p>Let's start with a topic that people will have seen many discussions around—interactive buttons. Take a look at the <a href="https://www.htmhell.dev/">latest postings on the HTMLHell site</a>, which will no doubt feature this issue heavily!</p>
<p>A button is often used to toggle or activate some dynamic functionality for a user. That could be to reveal a menu with important pages included, submit a form, toggle expandable content, and so on.</p>
<p>HTML includes the <code>&lt;button&gt;</code> element. This tells people that it can be interacted with and can help communicate the state of a component. By default, it is focusable, has key events, and comes with some browser default styles.</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">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>button<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>I'm a real button<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>Here we have some default browser styling making it <em>look like a button</em>, have focus behavior handled for us, and have key events mapped to it (<code>click</code>, <code>keyup</code>, <code>keydown</code>, etc) making it <em>act like a button</em>. Because <strong>it is a button!</strong></p>

<div data-demo="demo">
<button type="button" data-sanitized-class="button1">I'm a real button</button>
</div>

<p>Unfortunately, a pattern that is all too common–and used in the wrong circumstances–is to <a href="https://benmyers.dev/blog/clickable-divs/">turn a non-interactive element into a faux button</a>.</p>
<p>This will often be achieved with an ARIA 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>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>button<span data-sanitized-class="token punctuation">"</span></span> <span data-sanitized-class="token attr-name">tabindex</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 punctuation">&gt;</span></span>I'm not a button<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>
<div data-demo="demo">
<div role="button" tabindex="0" data-sanitized-class="button2">I'm not a button</div>
</div>

<p>This <code>&lt;div&gt;</code> (a non-semantic element designed for containing things) would now be announced as an interactive element by assistive technology, this is all well and good, but is it robust and accessible? No.</p>
<p>We're telling assistive technology that it's a button, but providing none of the functionality that comes with the native element.</p>
<p>As well as the role, we'd also then need to handle focus behavior manually using JavaScript and the <code>tabindex</code> attribute and also <a href="https://adrianroselli.com/2022/04/brief-note-on-buttons-enter-and-space.html">handle key events</a>. This adds unnecessary complexity and requires the user to download JavaScript just to do something that could be done with a native element.</p>
<h3 data-sanitized-id="extra-considerations">Extra considerations</h3>
<p>Whilst using a native button is a great start, there are other things to consider. Does your button have a suitable accessible name? (especially if it's an icon button). If the button has the purpose of taking a person to another page, it should be a link (<code>&lt;a&gt;</code>).</p>
<p>The following links are great resources for helping create a great button (or link).</p>
<ul>
<li><a href="https://css-tricks.com/a-complete-guide-to-links-and-buttons/">A complete guide to Links and buttons</a> on CSS-Tricks</li>
<li><a href="https://adrianroselli.com/2016/01/links-buttons-submits-and-divs-oh-hell.html">Links, Buttons, Submits, and Divs, Oh Hell</a> by Adrian Roselli</li>
</ul>
<h2 data-sanitized-id="lessselectgreater"><code>&lt;select&gt;</code></h2>
<p>A <code>&lt;select&gt;</code> is a control that provides a menu of options.</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>select<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>select<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>select<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>popularity<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>By popularity<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>price-low-high<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>By lowest price<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>price-high-low<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>By highest price<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>
<div data-demo="demo">
<label for="select">Sort by</label><br>
<select name="select" data-sanitized-id="select">
	<option value="popularity">By popularity</option>
	<option value="price-low-high">By lowest price</option>
	<option value="price-high-low">By highest price</option>
</select>
</div>
<p>When a person changes the option of the select, the value of it then becomes the value of the new option, nice! All browsers support this control and <a href="https://a11ysupport.io/tech/html/select_element">assistive technology support</a> is strong too. Screen readers announce the control's accessible name (our label in this example), how to open the select menu, the list of options, and then the value when selected.</p>
<p>For what is an important interaction for many products, it's surprising how many custom-built “select” controls there are in the wild. This normally comes down to a few reasons, all fairly related to each other:</p>
<ul>
<li>The design has come through and included elements other than text in the select options (checkboxes, images, multi-select functionality)</li>
<li>Select controls can be notoriously difficult to style, and the options even more so</li>
<li>Rendering inconsistencies between browsers/OS: Although the functionality remains consistent, a select and its states can look very different from one browser to another and especially with their options showing</li>
</ul>
<h3 data-sanitized-id="why-not-fake-a-select-though?">Why not <em>fake</em> a select though?</h3>
<p>It is of course possible to build something that looks and behaves like a <code>&lt;select&gt;</code> with other elements and a sprinkle of JavaScript and ARIA. It's also possible to make this into a robust and accessible solution; for example, <a href="https://24ways.org/2019/making-a-better-custom-select-element/">Julie Grundy's article</a> from 24 WAYS. This example uses semantic HTML and is careful in its usage of ARIA.</p>
<p>Whilst it may be doable, let's consider a few reasons it might still be better to suggest and use the native <code>&lt;select&gt;</code>.</p>
<h4>Future developer readability</h4>
<p>Whilst a more custom and complex approach may make sense to one developer who has followed an example/tutorial to build the component, a developer picking up bugs/changes/feature requests in the future may not have as good of an understanding of how all the elements have been set up and what their roles are supposed to be.</p>
<p>Although this could be solved with sufficient documentation, it's still extra work for somebody else to get up to speed with.</p>
<h4>Misconfiguration</h4>
<p>When using ARIA to add a role to an element to try and improve assistive technology communication, it can often require very specific roles to be included in parent/child element relationships. If misconfigured, not only will the whole component not announce correctly, but it's breaking accessibility and might cause more problems than it was used to solve!</p>
<p>The more complex and ARIA-heavy these custom components are—a custom select being a good example of one that could be with enough features—the more chance of this misconfiguration happening, especially concerning the previous point of somebody with less understanding picking up changes.</p>
<h4>Communicate with design—'shift left'</h4>
<p>Many accessibility issues can be solved during the design phase. The barriers we create are designed in, and the more we can shift the conversation and responsibility of accessibility to earlier in the product lifecycle, the better (often referred to as shifting left).</p>
<p>Constant and efficient communication between designers and developers can play a huge part in this. During sessions such as a design-developer handover, or <a href="https://www.figma.com/community/file/953682768192596304">accessibility annotation pairing</a>, it could be a great time to have a conversation about how a certain component design might lead to extra complexity, and to see if a native HTML element might be able to fit into the design.</p>
<p>Not only could this help educate a designer when it comes to semantics and accessibility considerations for future work, but it could also stop accessibility issues from getting to development or even to further down the line, when fixes/changes become much more expensive, or, even worse, end up unintentionally excluding people in production.</p>
<h3 data-sanitized-id="help-on-the-way?">Help on the way?</h3>
<p><a href="https://open-ui.org/">The Open UI project</a> is trying to make it easier for designers/developers to both use native controls for elements like <code>&lt;select&gt;</code> and to have the styling and functionality freedom that often turns people to use more complex custom solutions that can be inaccessible:</p>
<blockquote>The purpose of Open UI to the web platform is to allow web developers to style and extend built-in web UI controls, such as <code>&lt;select&gt;</code> dropdowns, checkboxes, radio buttons, and date/color pickers.
To do that, we'll need to fully specify the component parts, states, and behaviors of the built-in controls, as well as necessary accessibility requirements, and provide test suites to ensure compatibility. We'll also implement polyfills for our extensible web UI controls.
Whilst the project is still in its infancy, concerning the <code>&lt;select&gt;</code> element, there have been some developments with <code>&lt;selectmenu&gt;</code>. Whilst not ready for production yet, it can be <a href="https://open-ui.org/prototypes/selectmenu">enabled in Chromium-based browsers with a flag</a>. <code>&lt;selectmenu&gt;</code> allows greater customisation of the select control and the options that sit inside of it.</blockquote>
<p>You can read more about it in Hidde's article <a href="https://htmhell.dev/adventcalendar/2022/13/">“One day we'll have a fully customisable select”</a>.</p>
<h2 data-sanitized-id="lessnavgreater"><code>&lt;nav&gt;</code></h2>
<p>Navigation allows users to complete important journeys and find the key information they may need.</p>
<p>HTML includes the <code>&lt;nav&gt;</code> element. This is <a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/roles/landmark_role">a landmark element</a> and means it will automatically communicate to assistive technology that it's an element being used for navigation links (the same as adding <code>role="navigation"</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>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>Main<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>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>li</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 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 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 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 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>/history<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Our History<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 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 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>/contact<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Contact 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 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>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>nav</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>This is a perfectly accessible example of some navigation. <strong>No ARIA is needed</strong>. However, navigation can often require multiple levels of nested dropdowns, and become more complex. The example can still add this and be accessible, which we will take a look at, but first let's look at a pattern often reached for when it comes to navigation with dropdowns - <code>role="menu"</code>.</p>
<p>Whilst the naming of <code>role="menu"</code> and the child roles it requires ( <code>role="menuitem"</code>) may suggest that it'd be perfect to use for site navigation, the purpose of it is very different. This pattern is more for replicating desktop application menus. <a href="https://adrianroselli.com/2017/10/dont-use-aria-menu-roles-for-site-nav.html">Adrian Roselli has a superb article</a> explaining the difference.</p>
<p>You can see an example of how this would be marked up on the <a href="https://www.w3.org/WAI/ARIA/apg/example-index/menubar/menubar-navigation.html">aria authoring practices site</a>. Whilst there are cautionary recommendations at the top of the page detailing how this is unsuitable for site navigation, the page goes on to use it for one. This is an example of how just using these resources as a copy-and-paste solution can lead to bad practices.</p>
<p>Going back to how we can use <code>&lt;nav&gt;</code> and more semantic elements to start to create site navigation with multiple levels:</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>Main<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>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>li</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 attr-name">aria-current</span><span data-sanitized-class="token attr-value"><span data-sanitized-class="token punctuation attr-equals">=</span><span data-sanitized-class="token punctuation">"</span>page<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>#<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Home<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 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>#<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><br><span data-sanitized-class="highlight-line"></span><br>      <span data-sanitized-class="token tag"><span data-sanitized-class="token tag"><span data-sanitized-class="token punctuation">&lt;</span>button</span><br><span data-sanitized-class="highlight-line">        <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>button<span data-sanitized-class="token punctuation">"</span></span></span><br><span data-sanitized-class="highlight-line">        <span data-sanitized-class="token attr-name">aria-expanded</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><br><span data-sanitized-class="highlight-line">        <span data-sanitized-class="token attr-name">aria-controls</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-submenu<span data-sanitized-class="token punctuation">"</span></span></span><br>      <span data-sanitized-class="token punctuation">&gt;</span></span><br><span data-sanitized-class="highlight-line">        <span data-sanitized-class="token comment">&lt;!-- Visual cue icon - for example a downward facing chevron --&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>svg</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 attr-name">focusable</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">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><br><span data-sanitized-class="highlight-line">          <span data-sanitized-class="token comment">&lt;!-- Icon SVG code --&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>svg</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>Toggle About Us submenu<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>button</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 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>about-us-submenu<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>li</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 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 punctuation">&gt;</span></span>Our history<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 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 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 punctuation">&gt;</span></span>Meet the team<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 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>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>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 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 punctuation">&gt;</span></span>Work<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 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 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 punctuation">&gt;</span></span>Contact<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 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>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>nav</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>Here we're using nested unordered lists to mark up the second level of navigation, meaning that visually and semantically, the different levels of the menu item are related to each other, even without CSS and JavaScript loading.</p>
<p>You might be asking “but there is ARIA in there now, and you said we didn't need any?”. This is true, but we can use ARIA in the appropriate way to <strong>enhance</strong> the experience for people using assistive technology; we just shouldn’t solely rely on its <code>role</code> attribute to communicate that it's a navigation in the first place. Of course, JavaScript will also be needed to toggle some of these attributes, but, by default, without any of this our markup is semantic and accessible.</p>
<p>For a more detailed guide to building a semantic and accessible navigation, check out <a href="https://web.dev/website-navigation/">the web.dev navigation article by Manuel</a>.</p>
<h2 data-sanitized-id="lessul/olgreater"><code>&lt;ul/ol&gt;</code></h2>
<p>Lists (ordered and unordered) are very common elements used on sites. They both have semantic HTML elements:</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>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>li</span><span data-sanitized-class="token punctuation">&gt;</span></span>Unordered list item<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>Another unordered list item<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>Yet another unordered list item<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>ul</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<div data-demo="demo">
<ul>
  <li>Unordered list item</li>
  <li>Another unordered list item</li>
  <li>Yet another unordered list item</li>
</ul>
</div>
<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>ol</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>Ordered list item<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>Another ordered list item<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>Yet another ordered list item<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>ol</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<div data-demo="demo">
<ol>
	<li>Ordered list item</li>
	<li>Another ordered list item</li>
	<li>Yet another ordered list item</li>
</ol>
</div>
<p>They can help with things such as visually and semantically breaking down complex points, and they can give expectations of important steps to complete or consider. Communicating that a list with several items (and possibly links) exists can be important to people using assistive technology; for example, it can communicate how many items are in the list.</p>
<p>A common mistake that can be made is to just visually represent a list with a combination of other HTML elements; for example (<a href="https://htmhell.dev/30-bullet-list/">taken from HTMLHell</a>):</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">  • HTML</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>br</span> <span data-sanitized-class="token punctuation">/&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  • CSS</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>br</span> <span data-sanitized-class="token punctuation">/&gt;</span></span></span><br><span data-sanitized-class="highlight-line">  • JavaScript</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>Whilst this may visually represent a list, it is going to give people using assistive technology a very different experience. Each 'item' has no relation to the other. As it's just one paragraph element, this would give people no indication of how many items were present and how they relate in context and the order if they needed to be read sequentially.</p>
<h3 data-sanitized-id="who-would-do-that-though?">Who would do that though?</h3>
<p>Unordered lists were amongst the <a href="https://www.webdesignmuseum.org/web-design-history/tim-berners-lee-published-a-document-called-html-tags-1991">first 18 HTML tags released</a> so why do people still ignore them over just visually representing a list? And why are they so important? Aside from poor markup choices, there could be a few other reasons for this issue occurring.</p>
<h4>CMS WYSIWYG output</h4>
<p>It may not be apparent to somebody how to add lists in a content management system WYSIWYG editor, thus causing them to just visually create the list of items (for example using the bullet point shown in the previous example).</p>
<h4>Content editor skill gaps</h4>
<p>When content editors add content in a CMS it may be that they have misunderstood that using return to add items to a newline does not create a list, but it might visually appear to look like one to them in previews, etc.</p>
<h4>Markdown/other language confusion</h4>
<p>In some content language formats, such as markdown, lists can be added by using the hyphen/asterisk to indicate a list item, and these are then translated into correct list markup. It could be that somebody has mistakenly tried this thinking it might be the case.</p>
<h4>CSS advancements</h4>
<p>Ok, so this is an HTML-focused article, but let's not forget that CSS is amazing! What we can do with it in modern web development is incredible. It also makes being able to use semantic elements easier/more appealing if it was styling reasons they were not used for in the first place.</p>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::marker">The <code>::marker</code> pseudo element</a> enables styling on the bullet point of an u <code>ul</code>, whether it just be changing the colour of it, or adding custom content to it.</p>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@counter-style">There's also the <code>@counter-style</code> rule</a>. This enables the usage of non-standard bullet types but also can convert this to a string, meaning better accessibility considerations.</p>
<p>For ordered lists <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/counter-reset">the counter reset property</a> can help with custom styling numeric counters.</p>
<h3 data-sanitized-id="slight-tangent-incoming!">Slight tangent incoming!</h3>
<p>Educating content editors on using semantic markup can be an important part of ensuring that semantic, accessible content is being added to a site. Despite designing and building an accessible experience, this work could be undone by fundamental knowledge gaps when adding content such as blog posts, case studies, etc if they are handled through a CMS. Link text, image alt text, heading structure, correct element usage, etc. can all have detrimental effects on a person's experience.</p>
<p>If the importance of using semantic and accessible elements and structure is lost on somebody, it can be useful to remind people that it can have many benefits; for example, SEO and readability. Jeremy Keith has an interesting thought on <a href="https://adactio.com/journal/18199">doing the right things for the wrong reason</a>.</p>
<p>End of tangent.</p>
<h3 data-sanitized-id='lists-and-safari-"list"-itis'>Lists and Safari "list"-itis</h3>
<p>Something to consider when using lists and testing behavior with iOS/MacOS and Safari and VoiceOver, is the removal of default styles (<code>list-style: none;</code>). With this combination of OS and browser, this style will remove the semantics using the <code>&lt;ul&gt;</code> or <code>&lt;ol&gt;</code> element provides. The reasoning behind this comes from the overuse of lists to mark components up.</p>
<p>A bug was filed for this 'issue' which prompted the following response:</p>
<blockquote>This was a purposeful change due to rampant “list”-itis by web developers. … Basically, if you remove all default visible indication of the list, there is no indication to a sighted user or screen reader user that the content is a list. If you want to override this heuristic for accessibility, you can always add an explicit ARIA role=”list”.
As suggested to get around this, you can explicitly add a role to the element:</blockquote>
<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>ul</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>list<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 comment">&lt;!-- List items --&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>ul</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>Although this seems verbose (it'll also get flagged when validating HTML) and is an extra <em>thing</em> to remember, it'll make the experience much better for people using VoiceOver and encountering a list.</p>
<p><em><strong>Note</strong></em>: This is not needed when the <code>ul</code> is the child of a <code>nav</code> landmark element. In this case the <a href="https://twitter.com/cookiecrook/status/1612487416346193921">semantics of the list elements are preserved</a>(disclaimer: links to a Twitter thread), even if default styling is removed. Another great reason to make sure navigation is marked up semantically and accessibly.</p>
<p>So still announce list semantics if list was custom 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>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>Main<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>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>li</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 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 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 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 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>/history<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Our History<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 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 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>/contact<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Contact 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 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>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>nav</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<h2 data-sanitized-id="lessfieldsetgreater"><code>&lt;fieldset&gt;</code></h2>
<p>Forms are a critical part of many journeys on a site, but yet they are so often marked up inaccessibly or use patterns that do not take user needs into account. There are also many examples I've seen where native elements have been ignored in favor of overly complex solutions.</p>
<p>The <code>&lt;fieldset&gt;</code> and <code>&lt;legend&gt;</code> elements are a great way to break up more complex forms, and can greatly improve the flow and experience of filling a form out for many people:</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 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><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>How would you like to hear from us?<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 comment">&lt;!-- Checkboxes with selection options --&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>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>form</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>The <code>&lt;fieldset&gt;</code> element implicitly communicates a role of <code>group</code>—useful for grouping logically related items-and the <code>&lt;legend&gt;</code> provides the 'caption' or accessible name for it thus, communicating to assistive technology such as screen readers that the fields within are related and providing a label to announce.</p>
<p>Here's an example seen recently on a documentation site of using non-semantic elements to 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>form</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">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>my-radio-group<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Picked<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><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>group<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>my-radio-group<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 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>Field</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>picked<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>One<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">      One</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>Field</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>picked<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>Two<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">      Two</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>div</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 punctuation">&gt;</span></span>Picked: {values.picked}<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><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>button</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>submit<span data-sanitized-class="token punctuation">"</span></span><span data-sanitized-class="token punctuation">&gt;</span></span>Submit<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>form</span><span data-sanitized-class="token punctuation">&gt;</span></span></span></code></pre>
<p>This would result in a very similar experience to the fieldset and legend pattern but is just doing more work to get there. It's using non-semantic elements and using ARIA to turn them into something that can be done natively!</p>
<p>The issue with examples like this being included on documentation sites is that it runs the risk of being copied and pasted as an example, and then becoming habits in that codebase.</p>
<p>Other benefits native elements can offer would also have to be manually handled; for example, <code>&lt;fieldset&gt;</code> can take a <code>disabled</code> attribute, which would make all child input controls disabled.</p>
<h3 data-sanitized-id="other-form-element-tips">Other form element tips</h3>
<p>OK, so these do push this article over the 5 elements specified in the title. <em>However</em>, due to the number of times these issues come up on forms, and how low-hanging, high-impact they can be to fix, let's quickly mention them.</p>
<h4>Accessible input names</h4>
<p>Don't rely solely on placeholder attributes for input controls that require people to enter text/numbers etc. These can often fail colour contrast requirements, have patchy support for assistive technology, and aren't translated if internationalisation is required.</p>
<p>One solution could be to add an <code>aria-label</code> to the control, as this would provide an accessible name; however, even better would be to include an associated visual label for the control. This has benefits for many user groups.</p>
<p>Do also try to steer clear of the 'floating label' pattern. Although it does seem to strike a great balance between the designed 'placeholder' look and having a label, it can often introduce accessibility issues of its own, such as hard-to-read text and leaving the input feeling crowded.</p>
<h4>Validation messaging</h4>
<p>Ensure that colour alone is not being relied on to convey meaning in validation messaging. It can be nice UX (user experience) to include a suitable icon along with the message, for example, an exclamation with an error. If this can't be achieved, <a href="https://design-system.service.gov.uk/components/error-message/#be-clear-and-concise">ensure messaging is well-written</a>.</p>
<p>Make sure that the messaging is suitably announced to assistive technology. This can be done via an <a href="https://tink.uk/accessible-forms-with-aria-live-regions/">ARIA live region</a>. When we think about errors associated with inputs, in particular, not having this surfaced immediately could create barriers for people relying on using a form to complete a journey/access a vital service.</p>
<p><strong>Note</strong>: Although live regions are a great idea for important or time sensitive content like form errors. Be careful overusing it, it can become very 'noisy' and disruption on a person's journey.</p>
<h2 data-sanitized-id="summary">Summary</h2>
<p>In this article, we've covered only a small amount of the <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element">HTML elements available</a>. Each case reviewed how using a native HTML element can reduce complexity when building a component and the need for having to manually handle a range of possible interactions people using different input methods need to use, which requires JavaScript.</p>
<p>When reviewing a design, consider if you might be able to use a native HTML element to achieve the functionality, or consider having a conversation with design to see if something could change to allow you to do so. Communications such as accessibility annotation sessions can be useful for this.</p>
<p>HTML can do a lot, without needing to reach for and ship large chunks of JavaScript and potentially exclude whole groups of people interacting with a component. It's robust, semantic, and accessible. Take time to learn it, and where and when to use it.</p>
<h2 data-sanitized-id="further-reading">Further reading</h2>
<p>Some useful links to help learn more about using semantic and accessible HTML. Also how to use ARIA responsibly if needed.</p>
<ul>
<li><a href="https://web.dev/learn/html/">web.dev - learn HTML</a></li>
<li><a href="https://web.dev/learn/accessibility/">web.dev - learn accessibility</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Glossary/semantics#semantics_in_html">Why semantics matter</a>—reasoning and examples, should you need it</li>
<li><a href="https://inclusive-components.design/">Inclusive Components</a>—progressive, robust, semantic, and accessible common component patterns from Heydon Pickering</li>
<li><a href="https://www.w3.org/TR/aria-in-html/">Using ARIA</a>—including the 5 rules of ARIA</li>
<li><a href="https://www.w3.org/WAI/ARIA/apg/">ARIA authoring practices guide</a></li>
</ul>


guid: https://htmhell.dev/adventcalendar/2022/17/
title: Modern HTML as a foundation for progressive enhancement
author: ;Manuel Matuzovic
link: https://htmhell.dev/adventcalendar/2022/17/
hash: Y�leзN�^A�
attributes: {"enclosures":[]}
content:
<p>Reading HTMHell, you might be aware that progressive enhancement is a thing. To sum things up, it's a way to make sure anyone gets a viable version of your page whatever is their context — slow bandwitdh, oldish  browser, etc. — but also making the said page more resilient (e.g. to JavaScript errors).</p>
<p>Progressive enhancement starts from the ground up:</p>
<ol>
<li>content,</li>
<li>marked up with HTML,</li>
<li>styled with CSS,</li>
<li>enhanced with JavaScript</li>
<li>and improve accessibility with a bit of ARIA.</li>
</ol>
<p>Each of those steps should work as-is and enhance the lower steps without breaking them. In other words, you would need to write your markup independently from the CSS or JS you will apply later on.</p>
<p>Great.</p>
<p>That being said, it's kinda obvious that the better you know each step in the stack the more robust your page should be. JavaScript is everywhere so we may assume you know about it. ARIA is getting some shedlight for a few years now, so even without knowing ARIA we may suppose you use components libraries or something doing this just fine. CSS is constantly improving, I suppose you're following and discovering new CSS stuff every day or so.</p>
<p>But what about HTML? Is it part of your technical watch? How frequent are new HTML stuff popping out in your information sources? Not so often, I guess.</p>
<p>But hey. HTML is a living standard so specifications do change, browsers always improve support for HTML —as part of <a href="https://wpt.fyi/interop-2022">Interop 2022</a> for example— so there are new kids in town, either specified or implemented in browsers, and some of them are meant to be native controls replacing long-standing <code>&lt;div&gt;</code>-based JavaScript components.</p>
<p>What if we could improve the HTML stack for such components, making the markup step more resilient?</p>
<p><strong>Disclaimer</strong>: you need to think of HTML as a foundation, not a replacement for your existing JavaScript component. If your pattern needs ARIA, do not try to implement a low-elevel component. In other word, always try to provide the best possible user experience and don't care too much about developer experience. You may be interested in <a href="https://adrianroselli.com/2022/10/under-engineered-patterns-for-a11ytoconf.html#References">Adrian Roselli's under-engineered components blog posts serie</a>.</p>
<p>Let's go for a ride!</p>
<h2 data-sanitized-id="lessdetailsgreater-and-lesssummarygreater-as-a-aria-disclosure-pattern-foundation"><code>&lt;details&gt;</code> and <code>&lt;summary&gt;</code> as a ARIA disclosure pattern foundation</h2>
<p>Think of those "Show more" button thinggies where activating it make the content below appear. Making such component accessible currently require you to implement <a href="https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/">the ARIA disclosure design pattern</a>, basically using a button with <code>aria-expanded</code> attribute to communicate state.</p>
<p><code>&lt;details&gt;</code> and <code>&lt;summary&gt;</code> are a really good fit for this. As their names are pretty obvious, this markup pattern will display a summary and hide details—but make details available when activating the summary— and the <a href="https://thepaciellogroup.github.io/AT-browser-tests/test-files/details-summary.html">browsers implementation</a> and <a href="https://caniuse.com/details">support</a> are really good.</p>
<p>This feels quite right, isn't it? So why bother with the disclosure pattern at all and not use details and summary all the way? Well, interactions are not exactly what's expected by your users and support in browser and assistive technologies is not straightforward yet— <a href="https://www.scottohara.me/blog/2022/09/12/details-summary.html">as Scott O'Hara pointed out</a>.</p>
<p>But… may we use it as our foundation for an ARIA disclosure pattern? <a href="https://codepen.io/ffoodd/pen/XWYmmGj">Let's figure it out in a dedicated CodePen</a>!</p>
<p data-height="300" data-default-tab="html,result" data-slug-hash="XWYmmGj" data-user="ffoodd" data-sanitized-class="codepen">
  <span>See the Pen <a href="https://codepen.io/ffoodd/pen/XWYmmGj">
  Enhanced &lt;details&gt; with ARIA disclosure</a> by ffoodd (<a href="https://codepen.io/ffoodd">@ffoodd</a>)
  on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>Not much magic here: to improve and harmonize AT support, we make it a disclosure by adding to <code>&lt;summary&gt;</code> a button role and <code>aria-expanded</code> to convey state and make sure the disclosed content is hidden with the eponymous attribute. The <code>open</code> attribute on <code>&lt;details&gt;</code> handles this natively but <a href="https://www.scottohara.me/blog/2022/09/12/details-summary.html#impact-of-removing-the-default-disclosure-triangle">we can't rely on it as long as we override the default triangle marker</a> —which we will undoubtedly do: we must fully implement the disclosure pattern to prevent inconsistent rendering in browsers and ATs.</p>
<p>Moreover, did you know Chromium-based browsers allow collapsed details content discoverability using browser search? That's something coming to HTML with <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/hidden#the_hidden_until_found_state">the <code>until-found</code> value for the <code>hidden</code> attribute</a>, but that's not supposed to be the case of disclosed content when using the ARIA pattern.</p>
<p>As you may have understood, using <code>&lt;details&gt;</code> and <code>&lt;summary&gt;</code> enhanced with the ARIA disclosure pattern makes little to no difference for most users… but whenever your JS or CSS fails, your semantic markup would take over and stay interactive—with all its current limitations in ATs.</p>
<p>Also please be careful using those elements as a foundation: they aren't a good fit <a href="https://daverupert.com/2019/12/why-details-is-not-an-accordion/">for accordions</a>, <a href="https://melsumner.github.io/details-as-a-menu">a flyout menu</a>, <a href="https://cloudfour.com/thinks/a-details-element-as-a-burger-menu-is-not-accessible/">a burger menu</a>, <a href="https://adrianroselli.com/2019/04/details-summary-are-not-insert-control-here.html">a tab set or a dialog</a>… Stay semantic!</p>
<p>What if I told you there's more progressively enhanceable HTML elements like those? Wanna have a look?</p>
<h2 data-sanitized-id="lessoutputgreater-as-a-live-region"><code>&lt;output&gt;</code> as a live region</h2>
<p>Ever needed to populate a live region to communicate content changes to screen reader users—often being <a href="https://kittygiraudel.com/2016/10/13/css-hide-and-seek/">visually hidden with CSS</a>? That's quite common now, and you find live region handling in some frameworks: <a href="https://material.angular.io/cdk/a11y/overview#liveannouncer">Angular has a <code>LiveAnnouncer</code> in its Accessibility CDK</a>, <a href="https://make.wordpress.org/accessibility/handbook/markup/wp-a11y-speak/">WordPress has it <code>wp.a11y.speak()</code> internal script</a>… <a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions">ARIA live regions rely on three specific roles: <code>status</code>, <code>log</code> and <code>alert</code></a>, each having a slightly different behaviour.</p>
<p>But did you know there's an HTML element that's a native live region, with an implicit <code>status</code> role? <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/output">Meet &lt;output&gt;</a>! Its <a href="https://thepaciellogroup.github.io/AT-browser-tests/test-files/output.html">browser implementation is complete</a> and <a href="https://caniuse.com/mdn-html_elements_output">support is excellent</a>. However some specific browsers and ATs pairing are flawed, as <a href="https://www.scottohara.me/blog/2019/07/10/the-output-element.html">Scott O'Hara (again) pointed out</a>.</p>
<p><a href="https://codepen.io/ffoodd/pen/rNvqGBB">Let's make <code>&lt;output&gt;</code> more robust by making it an ARIA live region, on CodePen</a>!</p>
<p data-height="300" data-default-tab="html,result" data-slug-hash="rNvqGBB" data-user="ffoodd" data-sanitized-class="codepen">
  <span>See the Pen <a href="https://codepen.io/ffoodd/pen/rNvqGBB">
  Enhanced &lt;output&gt; with status role</a> by ffoodd (<a href="https://codepen.io/ffoodd">@ffoodd</a>)
  on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>As you may remember, expliciting HTML elements roles was quite needed a few years ago for landmarks mostly to improve support in browsers and ATs —and still recommended in some accessibility guidelines like <a href="https://www.numerique.gouv.fr/publications/rgaa-accessibilite/methode-rgaa/criteres/#crit-12-6">the French RGAA</a>. We got used to write <code>&lt;main role="main"&gt;</code>, <code>&lt;header role="banner"&gt;</code> and so on. What's also good with <code>&lt;output role="status"&gt;</code> is that it allows you to style your live regions by selecting the output element: lower specificity, and some kind of soft reset too —CSS containment, maybe?</p>
<h3 data-sanitized-id="a-more-specific-live-region-toast!">A more specific live region: toast!</h3>
<p>There's also a case for visually displayed live regions: toasts! I won't go way further on the topic, because it's been explored in a wide variety of posts: <a href="https://www.scottohara.me/blog/2019/07/10/the-output-element.html">Scott O'Hara already mentionned <cite>The output element</cite></a>, a technical follow-up of his <a href="https://www.scottohara.me/blog/2019/07/08/a-toast-to-a11y-toasts.html"><cite>A toast to an accessible toast…</cite> addressing UX concerns)</a>, and <a href="https://adrianroselli.com/2020/01/defining-toast-messages.html">Adrian Roselli in <cite>Defining toast messages</cite></a>.</p>
<p><strong>Warning</strong>: if your toast or live region contains interactive elements, it should probably use a <code>dialog</code> or <code>alertdialog</code> role, and preferably not an <code>&lt;output&gt;</code> element at all. But… there might be another HTML element for that!</p>
<h2 data-sanitized-id="a-modal-lessdialoggreater">A modal <code>&lt;dialog&gt;</code></h2>
<p>I won't go that deep with <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog">the <code>&lt;dialog&gt;</code> element</a>, but let's explore what it does natively compared to <a href="https://www.w3.org/WAI/ARIA/apg/patterns/dialogmodal/">the ARIA dialog design pattern</a>:</p>
<ul>
<li>it has an implicit <code>dialog</code> role,</li>
<li>when opened with the <code>.showModal()</code> method:
<ul>
<li>it has an implicit <code>aria-modal="true"</code> property,</li>
<li>it's closable with the <kbd>Escape</kbd> key,</li>
</ul>
</li>
<li>it traps focus in the dialog —but allows to get out of the browser frame…</li>
<li>it restores focus to the opening element when closing the dialog,</li>
<li>it makes the document <a href="https://developer.mozilla.org/docs/Web/API/HTMLElement/inert"><code>inert</code></a> automatically.</li>
</ul>
<p>And there's more:</p>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::backdrop">the <code>::backdrop</code> pseudo-element</a> allows you to style your dialog overlay really easily,</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:modal">the <code>:modal</code> pseudo-class</a> applies when opening dialog with the <code>.showModal()</code> method,</li>
<li>if your dialog contains a form, using <code>method="dialog"</code> form attribute makes your submit button to close the dialog.</li>
</ul>
<p>Dialog element on its own isn't consistent enough in browsers and ATs (yet), <a href="https://www.scottohara.me/blog/2019/03/05/open-dialog.html">as Scott O'Harra (again) pointed out</a>, but you got the idea: what about enhancing it by applying the ARIA dialog pattern to it, and relying on its standard behaviour to save a few lines of JavaScript? That's more or less what <a href="https://web.dev/building-a-dialog-component/">Adam Argyle explored in his dialog component pattern on web.dev</a> with some nice little tricks to learn —however keep in mind <a href="https://twitter.com/aardrian/status/1586792250113232896">web.dev patterns aren't battle-tested with ATs nor against WCAG</a>. <a href="https://css-tricks.com/dialog-components-roll-your-own/">Building a dialog component is not straightforward</a>, and <a href="https://www.smashingmagazine.com/2021/07/accessible-dialog-from-scratch/">Kitty Giraudel goes in details about what's needed to make an <cite>accessible dialog from scratch</cite></a>. Since those posts, the dialog support has improved quite a lot and is even <a href="https://wpt.fyi/interop-2022">part of Interop 2022</a>, so expect it to improve again this year's last month.</p>
<p>This is probably the least obvious case, since speaking of progressive enhancement the <code>&lt;dialog&gt;</code> element might be a bad choice: it simply cannot work without JavaScript. But if your JavaScript fails for any reason, your event handlers might still work.</p>
<h2 data-sanitized-id="conclusion">Conclusion</h2>
<p>HTML is awesome. It's obviously not enough to provide a fully accessible experience to users, as <a href="https://daverupert.com/2020/02/html-the-inaccessible-parts/">Dave Rupert highlighted two years ago in <cite>HTML: the inaccessible parts<cite></cite></cite></a> — even if some of those examples are not accurate anymore, fixed in either browser or ATs.</p>
<p>But not being perfect is probably still better than being neutral, isn't it?</p>
<p>I think that's the kind of thing HTML unveils: at some point, details and summary shall be consistently implemented and exposed to ATs, making ARIA enhancements pointless. Scott's work, from advanced testing to blog posts and filing bugs, are the way forward. Fully implemented patterns in libraries like <a href="https://a11y-dialog.netlify.app/">Kitty Giraudel's a11y-dialog</a> are what alllows maturity and clarify expectations. And as usage increases, browsers and ATs will eventually consider prioritization, in Interop or <a href="https://aria-at.w3.org/">ARIA-AT</a>.</p>
<p>Let's use, test and help browsers and ATs support those newer HTML elements!</p>


