<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>tempertemper</title>
  <subtitle>Articles on user experience design and frontend web development</subtitle>

  <link href="https://www.tempertemper.net/feeds/main.xml" rel="self" />
  <link href="https://www.tempertemper.net" rel="alternate" type="text/html" />

  <id>https://www.tempertemper.net/feeds/main.xml</id>

  <updated>2026-05-30T00:00:00Z</updated>

  <rights type="html">&amp;copy; copyright 2009 to 2026, tempertemper Web Design Ltd</rights>
  <logo>https://www.tempertemper.net/assets/img/tempertemper-feed.png</logo>
  <icon>https://www.tempertemper.net/assets/img/icons/favicon.png</icon>

  <author>
    <name>Martin Underhill</name>
    <email>hello+website@tempertemper.net</email>
    <uri>https://mastodon.social/@tempertemper</uri>
  </author>
  <entry>
    <title>Do it properly now</title>
    <link href="https://www.tempertemper.net/blog/do-it-properly-now" />
    <id>https://www.tempertemper.net/blog/do-it-properly-now</id>

    
    <published>2026-05-30T00:00:00Z</published>
    <updated>2026-05-30T00:00:00Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Shipping something inaccessible is rarely a shortcut; it’s usually a debt.</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>I had the privilege to be among some great speakers at this year’s <a href="https://accessgiven.co.uk">Access:Given conference</a>; there were so many excellent insights, but one has really stuck with me.</p>
<p>In the early afternoon panel discussion, <a href="https://www.linkedin.com/in/nathan-rowland/">Nathan Rowland</a> was talking about building inaccessible products when he dropped this gem:</p>
<blockquote>
<p>There is nothing more permanent than a temporary solution.</p>
</blockquote>
<p>I love this! I caught up with Nathan afterwards and he said it was something his grandfather used to say about woodworking. It goes back to that <a href="/blog/if-youre-going-to-do-a-job-do-it-properly">job-half-done idea</a>, but makes it an even scarier prospect.</p>
<p>We design and build digital products for other people to use, and other people might (will!) <a href="/blog/designing-and-building-from-our-own-worldview">use our products in ways we didn’t expect</a>. Accessibility is partly about anticipating this unknown.</p>
<p>If we ship a subpar feature or update to our product, what’s the likelihood of going back to put it right?</p>
<p>Other priorities creep in, team members change, and that temporarily inaccessible work is forgotten. It gets built on top of. And the longer it sits there, the more expensive and awkward it is to fix.</p>
<p>That doesn’t mean everything has to be <em>perfect</em>; it just means accessibility can’t be treated as something we’ll tidy up later.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/do-it-properly-now">Do it properly now</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Do graphs and charts need to be accessible?</title>
    <link href="https://www.tempertemper.net/blog/do-graphs-and-charts-need-to-be-accessible" />
    <id>https://www.tempertemper.net/blog/do-graphs-and-charts-need-to-be-accessible</id>

    
    <published>2026-04-29T00:00:00Z</published>
    <updated>2026-04-29T00:00:01Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Charts and graphs are a good example of where making content accessible is not always the same as making an image itself accessible.</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>Everything should be accessible. Or should it? Charts and graphs are a great example of where you <em>can</em> make something accessible, but maybe you shouldn’t. Bear with me here.</p>
<p>Pie charts, line graphs, bar and column charts (let’s just call them all ‘charts’ for ease) are really useful, visual ways to present data, and we’d include one on a webpage using an image, like a PNG or SVG.</p>
<h2 id="accessible-pngs">Accessible PNGs</h2>
<p>I say ‘PNGs’, but these could be any other image format, like WebP, AVIF, or even JPG. The mechanism we’d use to embed them on our page would be the <code>&lt;img /&gt;</code> element:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>my-great-chart.png<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>A description of the information the chart conveys<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code></pre>
<p>Depending on the complexity of the chart, our <code>alt</code> text could be doing a lot of work here. In principle, that’s fine, as the <code>alt</code> attribute can contain as many characters as you need, but the problem is that there’s no way of introducing any meaning to the content in <code>alt</code> text; it’s just a wall of unstructured text.</p>
<p>Here’s an example with some made-up figures about people’s favourite characters from the original Star Wars trilogy:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>star-wars-favourites.png<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Pie chart showing that 22% chose Han Solo, 18% chose Darth Vader, 15% chose Princess Leia, 12% chose Chewbacca, 9% chose Luke Skywalker, 7% chose Yoda, 6% chose Obi-Wan Kenobi, 4% chose Lando Calrissian, 3% chose R2-D2, 2% chose C-3PO, and 2% chose other characters.<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code></pre>
<p>That’s a fairly typical amount of information for a chart, and it takes a fair amount of concentration to make sense of, especially with so much repetitive language. Imagine more complex charts, like a <a href="https://en.wikipedia.org/wiki/Bar_chart#Grouped_(clustered)_and_stacked">stacked column chart</a> or a <a href="https://en.wikipedia.org/wiki/Line_chart#Best-fit">best-fit line chart</a>.</p>
<h3 id="before-you-mention-longdesc">Before you mention <code>longdesc</code>…</h3>
<p>I know what you’re thinking: there’s the <code>longdesc</code> attribute, which allows us to reference a structured HTML document:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>star-wars-favourites.png<span class="token punctuation">"</span></span> <span class="token attr-name">longdesc</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>star-wars-favourites-description.html<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code></pre>
<p>Although browser support still appears to be there, <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/longDesc"><code>longdesc</code> is long deprecated</a> so definitely not recommended.</p>
<h2 id="accessible-svgs">Accessible SVGs</h2>
<p>So if <code>alt</code> text isn’t ideal, and <code>longdesc</code> is out, maybe a more complex image format like SVG is the answer?</p>
<p>We could reference an SVG file just as we did with the PNG in our last example, but <a href="https://cariefisher.com/a11y-svg-alts/">for inline SVGs</a> the result is exactly the same; a big lump of unstructured descriptive text:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>svg</span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>img<span class="token punctuation">"</span></span> <span class="token attr-name">aria-labelledby</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>title description<span class="token punctuation">"</span></span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2000/svg<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>title<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Pie chart showing people's favourite characters from the original Star Wars trilogy<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>desc</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>description<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>22% chose Han Solo, 18% chose Darth Vader, 15% chose Princess Leia, 12% chose Chewbacca, 9% chose Luke Skywalker, 7% chose Yoda, 6% chose Obi-Wan Kenobi, 4% chose Lando Calrissian, 3% chose R2-D2, 2% chose C-3PO, and 2% chose other characters.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>desc</span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!-- SVG coordinates --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>svg</span><span class="token punctuation">></span></span></code></pre>
<h3 id="aria-in-svg">ARIA in SVG</h3>
<p>But we’ve been ignoring SVG’s superpowers! SVG is markup, so ARIA can be used to add semantics to the elements that make it up.</p>
<p>In <a href="https://tink.uk/accessible-svg-line-graphs/">Accessible SVG line graphs</a>, Léonie Watson goes into detail about how we can make purposeful use of SVG’s group (<code>&lt;g&gt;</code>) element and various ARIA role attributes to give the chart table semantics. A chart is a visual representation of tabular data, after all!</p>
<p>For our Star Wars pie chart, we could use:</p>
<ul>
<li><code>role=&quot;table&quot;</code> for the containing group</li>
<li><code>role=&quot;row&quot;</code> for each character</li>
<li><code>role=&quot;columnheader&quot;</code> to label each column of information (character name, and percentage of votes)</li>
<li><code>role=&quot;rowheader&quot;</code> for each character name</li>
<li><code>role=&quot;cell&quot;</code> for each percentage value</li>
</ul>
<p>Visually a chart; semantically a table.</p>
<h2 id="one-thing-visually-another-non-visually">One thing visually, another non-visually</h2>
<p>I love the ARIA in SVG approach, but it’s fiddly enough to make me wonder if there’s a simpler approach. We could separate the two things:</p>
<ul>
<li>An SVG chart that’s hidden from assistive technologies with <code>role=&quot;presentation&quot;</code> or <code>aria-hidden=&quot;true&quot;</code></li>
<li>An HTML table that’s <a href="/blog/hierarchy-in-tables#visually-hidden-text">hidden visually with CSS, but still available to screen reader users</a></li>
</ul>
<p>This way, sighted users would see the chart and screen reader users would get the data in an HTML table. That would work, but it still assumes the table is only useful to screen reader users.</p>
<h2 id="just-show-the-underlying-data">Just show the underlying data</h2>
<p>Maybe we should stop treating the table as an accessibility-only fallback? I reckon it could be even better to present both the visualisation and the underlying data. After all, some people might prefer rows and columns to a chart.</p>
<p>The way I’d probably approach this is to ensure the chart doesn’t get picked up by assistive technology like screen reader software at all, as we did before:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>svg</span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>presentation<span class="token punctuation">"</span></span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2000/svg<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!-- SVG contents --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>svg</span><span class="token punctuation">></span></span></code></pre>
<p>And then our table:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>table</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>caption</span><span class="token punctuation">></span></span>Favourite characters from the original Star Wars trilogy<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>caption</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tr</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">></span></span>Character<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">></span></span>Percentage of votes<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tr</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tr</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">></span></span>Han Solo<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">></span></span>22%<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tr</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tr</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">></span></span>Darth Vader<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">></span></span>18%<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tr</span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!-- The rest of the characters --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>table</span><span class="token punctuation">></span></span></code></pre>
<p>If your table has a lot of data, you could save some unnecessary scrolling for users who prefer the chart by wrapping it in a <code>&lt;details&gt;</code>/<code>&lt;summary&gt;</code> element.</p>
<p><i>Note: it’s totally valid to expose the chart to screen reader users if the visual presentation is relevant; just make sure the alternative text describes the visual presentation, not the data that’s already available in the table.</i></p>
<h2 id="so-what-to-do">So what to do?</h2>
<p>For screen reader users, a simple chart with the data in the <code>alt</code> text might be okay, but more often than not we probably want to present the data in tabular format, which is easier to navigate, compare, and understand. Going one step further by accompanying the chart with a table is an even more robust approach as it also allows sighted users to choose how best to absorb the information.</p>
<p>So do charts and graphs need to be accessible? Yes and no. The chart image itself doesn’t always need to be exposed to assistive technologies, but the information it communicates must be accessible.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/do-graphs-and-charts-need-to-be-accessible">Do graphs and charts need to be accessible?</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>A bugbear about aria-label</title>
    <link href="https://www.tempertemper.net/blog/a-bugbear-about-aria-label" />
    <id>https://www.tempertemper.net/blog/a-bugbear-about-aria-label</id>

    
    <published>2026-03-31T00:00:00Z</published>
    <updated>2026-03-31T00:00:02Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Labels are labels and names are names, except aria-label which is a name…</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>I was writing about <a href="/blog/theres-no-need-to-include-navigation-in-your-navigation-labels">how to write the <code>aria-label</code> for <code>&lt;nav&gt;</code> elements</a> and I kept referring to the <code>aria-label</code> as the ‘label’, which bothered me.</p>
<p>You know how pernickety I can get about what things are called; I mean, I wrote over 600 words on <a href="/blog/headers-headings-and-titles">why not to use ‘headers’ and ‘headings’ interchangeably</a>. So allow me to dig into why the ‘label’ bit of <code>aria-label</code> gets on my nerves.</p>
<p>Let’s use the Web Content Accessibility Guidelines (WCAG) as our reference point for the terminology. Here’s their <a href="https://www.w3.org/TR/wcag/#dfn-labels">definition for ‘label’</a>:</p>
<blockquote>
<p>text or other component with a text alternative that is presented to a user to identify a component within web content</p>
</blockquote>
<p>It’s referring to what is presented <em>visually</em>; usually text or something else with a ‘text alternative’, like an icon.</p>
<p>WCAG then goes on to <a href="https://www.w3.org/TR/wcag/#dfn-name">define a ‘name’</a> as:</p>
<blockquote>
<p>text by which software can identify a component within web content to the user</p>
</blockquote>
<p>So this is always text, and specifically about how software uses text to convey something to the user. It’s about the underlying <i>accessible name</i>. That might match the label, but it won’t if the label is:</p>
<ul>
<li>an icon</li>
<li>a shortened version of a longer, more descriptive name, relying on surrounding content for visual context</li>
</ul>
<p>Maddeningly, the <a href="https://w3c.github.io/aria/#aria-label">ARIA spec describes <code>aria-label</code></a> in terms of it being a ‘name’ too:</p>
<blockquote>
<p>It provides the user with a recognizable name of the object. The most common accessibility API mapping for a label is the accessible name property</p>
</blockquote>
<p>So my article about <code>aria-label</code> for <code>&lt;nav&gt;</code> elements was much easier to read when talking about <code>aria-label</code>s as if they were labels, but it wasn’t technically correct. If <code>aria-label</code> is always used to give something a ‘name’, wouldn’t <code>aria-name</code> have made more sense…?</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/a-bugbear-about-aria-label">A bugbear about aria-label</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>There’s no need to include ‘navigation’ in your navigation labels</title>
    <link href="https://www.tempertemper.net/blog/theres-no-need-to-include-navigation-in-your-navigation-labels" />
    <id>https://www.tempertemper.net/blog/theres-no-need-to-include-navigation-in-your-navigation-labels</id>

    
    <published>2026-03-30T00:00:00Z</published>
    <updated>2026-03-30T00:00:03Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Marking up navigation is pretty straightforward, but here’s a nice reminder on how the aria-label should be written.</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>When you mark up your website, groups of links are probably going to be wrapped in <code>&lt;nav&gt;</code> elements. If you have more than one, you’re going to have to label each of them so that screen reader users know what each is for.</p>
<p>I’ve written about <a href="/blog/how-navigation-should-work-for-keyboard-users">How navigation should work for keyboard users</a>, which includes a healthy dollop of instructions for making screen reader users’ experiences decent too.</p>
<p>I talked about using <code>aria-label</code> to differentiate each <code>&lt;nav&gt;</code> group, but I didn’t really mention <em>how</em> to write your labels. Here’s the example I used:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>nav</span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Primary<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/home<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Home<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/about<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>About<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/contact<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Contact<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>nav</span><span class="token punctuation">></span></span></code></pre>
<p>Just “Primary”. Doesn’t look like much, but it’s enough. You see, screen reader software announces three things:</p>
<ul>
<li>The role of the element</li>
<li>The name of the element</li>
<li>The state of the element, if applicable</li>
</ul>
<p>We’re not concerned with the state in this example (if there was a sub-navigation with a button that triggered it, it’d have a state depending on whether it was opened and closed); here we’re interested in the role and the name.</p>
<p>The role is gleaned from the <code>&lt;nav&gt;</code> element, which has an implicit <code>role=&quot;navigation&quot;</code>. This lets screen reader users know they’ve arrived at “navigation”.</p>
<p>The name is the <i>accessible name</i> of the element, conveyed by the <code>aria-label</code> attribute: “Primary”. This might be “Secondary” for another navigation group, or something like “Social”, depending on the purpose.</p>
<p>So screen reader software is going to announce something along the lines of “Navigation, Primary” or “Primary navigation landmark”.</p>
<p>And now to the reason I wrote this post: including the word “navigation” in your <code>&lt;nav&gt;</code> labels. There’s no need. If we did, we’d hear something like “Navigation, Primary navigation”. Not the end of the world, but unnecessarily repetitive for screen reader users.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/theres-no-need-to-include-navigation-in-your-navigation-labels">There’s no need to include ‘navigation’ in your navigation labels</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Figcaptions versus alt text</title>
    <link href="https://www.tempertemper.net/blog/figcaptions-versus-alt-text" />
    <id>https://www.tempertemper.net/blog/figcaptions-versus-alt-text</id>

    
    <published>2026-02-28T00:00:00Z</published>
    <updated>2026-02-28T00:00:04Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>How does an image’s descriptive (alt) text differ from the caption it would have if it were used in a &lt;figure&gt; element?</summary>
        <category term="Accessibility" />
        <category term="Content" />
        <category term="HTML" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>I’ve had the same conversation more than once about how a <code>&lt;figure&gt;</code> element’s caption should be used, and how that differs from an image’s <code>alt</code> text.</p>
<h2 id="image-descriptions">Image descriptions</h2>
<p>Before we go into the difference, it’s important to understand what <code>alt</code>, or descriptive, text is. The Web Content Accessibility Guidelines (WCAG) provides some clarity in <a href="https://www.w3.org/TR/WCAG22/#non-text-content">Non-text Content</a>, which covers image <code>alt</code> text:</p>
<blockquote>
<p>All non-text content … has a text alternative that serves the equivalent purpose</p>
</blockquote>
<p>The <code>alt</code> text must convey the same message as the image. This means that anybody who can’t see an image can still understand the meaning it’s communicating.</p>
<p>As a quick aside, there are a few things that I won’t get into:</p>
<ul>
<li>Images that don’t convey meaning: these wouldn’t make sense to use in a <code>&lt;figure&gt;</code> element</li>
<li>How detailed, or otherwise, the description of the image should be</li>
<li>Other things that can be used in a <code>&lt;figure&gt;</code> element, like code, video, or just plain old text</li>
</ul>
<h2 id="captions">Captions</h2>
<p>Okay, so now we know what <code>alt</code> text is, let’s talk about <code>&lt;figcaption&gt;</code> and how it’s different. First, the markup pattern; here’s a typical <code>&lt;figure&gt;</code> element that uses an image:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>figure</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>example.jpg<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Image description<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>figcaption</span><span class="token punctuation">></span></span>The caption<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>figcaption</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>figure</span><span class="token punctuation">></span></span></code></pre>
<p>The <code>&lt;figure&gt;</code> groups an image, its descriptive text, and a <code>&lt;figcaption&gt;</code>. <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/figcaption">MDN Docs has this to say</a>:</p>
<blockquote>
<p>The <code>&lt;figcaption&gt;</code> HTML element represents a caption or legend describing the rest of the contents of its parent <code>&lt;figure&gt;</code> element</p>
</blockquote>
<p>Not too much to go on, so let’s think about captions. <a href="https://www.merriam-webster.com/dictionary/caption">Merriam Webster</a> has a nice explanation of the word ‘caption’ in our context:</p>
<blockquote>
<p>the explanatory comment or designation accompanying a pictorial illustration</p>
</blockquote>
<p>So we’re not talking about describing the image, which would be repetitive; we’re explaining what part the image plays in what we’re writing.</p>
<h2 id="some-examples">Some examples</h2>
<p>I’ve always found this a bit abstract, and better explained with examples.</p>
<h3 id="a-simple-photo">A simple photo</h3>
<p>Let’s start with the image I use on my <a href="/about">About page</a> (I’ll strip away the <code>&lt;picture&gt;</code> markup I use over there for simplicity’s sake):</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/assets/img/martin-underhill-tempertemper.jpg<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>A friendly white man with a bald head, short brown beard, and glasses. He's wearing a casual dark blue shirt and is leaning against a grey stone wall, nursing a cup of tea.<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code></pre>
<p>The image’s context, placed directly after the intro paragraph about me, means that readers will know it’s a picture of me. And you’ll note that with the <code>alt</code> text alone you get a good flavour of what the image is communicating.</p>
<p>Now let’s imagine the same image appeared on a longer page which referenced a few people, where the reader might not know that the picture was of me. We might do this:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>figure</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/assets/img/martin-underhill-tempertemper.jpg<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>A friendly white man with a bald head, short brown beard, and glasses. He's wearing a casual dark blue shirt and is leaning against a grey stone wall, nursing a cup of tea.<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>figcaption</span><span class="token punctuation">></span></span>Martin Underhill of tempertemper<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>figcaption</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>figure</span><span class="token punctuation">></span></span></code></pre>
<p>The content preceding and following the image no longer has to lead directly into or out of it, since it’s accompanied by the “Martin Underhill of tempertemper” caption.</p>
<p>This pattern works well for other articles, for example an article about football:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>figure</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>a-tackle.jpg<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Two footballers aggressively challenging for the ball in the air; the player in black and white has reached the ball with his head before the one in light blue<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>figcaption</span><span class="token punctuation">></span></span>Newcastle United's Dan Burn kept Manchester City's Erling Haaland quiet for most of the game<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>figcaption</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>figure</span><span class="token punctuation">></span></span></code></pre>
<h3 id="multiple-images">Multiple images</h3>
<p>I’ve done a fair bit of <a href="/services/audits">accessibility auditing</a> in my time, and I often find the same issue in multiple places. Instead of raising an issue for each, I usually list all the occurrences in a single issue.</p>
<p>One image and a bulleted list for each occurrence usually does the job here, but sometimes the same issue might look slightly different in different places; in which case I’ll group those variations together under a <code>&lt;figure&gt;</code> and explain why they’re relevant with a single caption:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>figure</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>issue1a.png<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>A text link that has keyboard focus but no visible focus state<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>issue1b.png<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>A button that has keyboard focus but no visible focus state<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>issue1c.png<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>A checkbox that has keyboard focus but no visible focus state<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>figcaption</span><span class="token punctuation">></span></span>Keyboard focus states are not present<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>figcaption</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>figure</span><span class="token punctuation">></span></span></code></pre>
<p>The key thing here is that all images should demonstrate the same point.</p>
<h3 id="reference">Reference</h3>
<p>Again when auditing, I sometimes have the opposite situation, where one image would illustrate multiple issues raised. I could repeat the same image on each issue, but sometimes it can be more reader-friendly to use a single image in the first issue, numbered in its caption, and reference it from each subsequent issue:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>figure</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>figure1.png<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>A list of icons, each representing a different service that is on offer.<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>figcaption</span><span class="token punctuation">></span></span>Figure 1: Icons are used instead of visible text for navigation to each service.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>figcaption</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>figure</span><span class="token punctuation">></span></span></code></pre>
<p>I might then reference ‘Figure 1’ in a number of separate-but-related accessibility issues that are caused by <a href="/blog/what-i-wish-was-in-wcag-prohibit-icon-only-buttons">using icons instead of text</a>.</p>
<h3 id="interesting-formats">Interesting formats</h3>
<p>If the image is a photo, screen grab, illustration, the JPG or PNG format is fine (or something similar like <a href="/blog/using-webp-images">WebP</a> or <a href="/blog/avif-image-compression-is-incredible">AVIF</a>), but sometimes a diagram or chart might be best as an SVG. You can reference the SVG from an <code>&lt;img /&gt;</code> element, of course, but you can also embed the SVG directly on the page:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>figure</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>svg</span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>500<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>200<span class="token punctuation">"</span></span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0 0 500 200<span class="token punctuation">"</span></span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2000/svg<span class="token punctuation">"</span></span> <span class="token attr-name">aria-labelledby</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>logoTitle<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>logoTitle<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
            A line graph showing newsletter subscriber growth over time, with an overall upward trend and a sharp increase in early 2025.
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span>
        <span class="token comment">&lt;!-- SVG paths --></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>svg</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>figcaption</span><span class="token punctuation">></span></span>Newsletter subscribers continue to increase over time<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>figcaption</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>figure</span><span class="token punctuation">></span></span></code></pre>
<p>In this case, the <code>&lt;title&gt;</code> gives a concise equivalent of what the chart conveys. If readers need more detail; for example exact dates, plateaus, or growth rates; that explanation is often better placed in the surrounding content (maybe in an accompanying table?) rather than crammed into the image’s descriptive text.</p>
<h2 id="replacing-versus-explaining">Replacing versus explaining</h2>
<p>Not every image needs a <code>&lt;figure&gt;</code> and <code>&lt;figcaption&gt;</code>; an <code>&lt;img /&gt;</code> with well-written <code>alt</code> text in the right context is often enough. But if the image (whether visually or through its descriptive text) doesn’t stand on its own, you probably need a caption to explain what the image adds to the page.</p>
<p>So <code>alt</code> and caption should never be the same. One replaces the image; the other supports it.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/figcaptions-versus-alt-text">Figcaptions versus alt text</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Designing and building from our own worldview</title>
    <link href="https://www.tempertemper.net/blog/designing-and-building-from-our-own-worldview" />
    <id>https://www.tempertemper.net/blog/designing-and-building-from-our-own-worldview</id>

    
    <published>2026-01-30T00:00:00Z</published>
    <updated>2026-01-30T00:00:05Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Producing accessible software means continually questioning your own habits and assumptions about how people interact with it.</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>We tend to design and build our digital products from our own worldview, not thinking about the many other ways people might use them. This is totally natural, and it’s why accessibility exists: to continually remind people who design and build that <em>their</em> experience of the world is not the <em>only</em> one.</p>
<p>We often end up in a position where we haven’t considered accessibility, so all that functionality has to be added retrospectively which means:</p>
<ul>
<li><a href="/blog/accessibility-by-degrees">the project cost ends up <em>much</em> higher</a></li>
<li><a href="/blog/making-sense-of-accessibility-and-the-law">legal action</a> has been a real possibility</li>
<li><a href="/blog/if-youre-going-to-do-a-job-do-it-properly">the job was only part-done</a></li>
<li>a <em>lot</em> of people will have been excluded</li>
</ul>
<h2 id="that-common-misconception">That common misconception</h2>
<p>The way I use the web and apps is pretty common:</p>
<ul>
<li>Touch on my phone</li>
<li>Mouse or trackpad on my laptop</li>
</ul>
<p>There’s the keyboard on my laptop too, of course, that I use to type into text boxes. And that’s how the majority of people negotiate their devices.</p>
<p>But that’s not the only way. People use all sorts of different, as the Web Content Accessibility Guidelines (WCAG) calls them, <a href="https://www.w3.org/TR/wcag/#input-modalities">input modalities</a>. In fact, even from my own perspective, mouse/trackpad and touch is only superficially how I get around: I make very heavy use of my keyboard beyond typing text.</p>
<h2 id="how-i-use-the-keyboard">How I use the keyboard</h2>
<p>I love efficient workflows, and using the keyboard on my laptop plays a huge part in speeding things up.</p>
<h3 id="web-page-navigation">Web page navigation</h3>
<p>If I’m filling out a form on a web page, rather than take my fingers off the keys and onto my trackpad or mouse to move from field to field, I tend to fly through using <kbd>⇥</kbd> (Tab). I’ll keep my fingers over the keys to check/uncheck checkboxes and press in-form buttons using <kbd>Space</kbd>, and I usually try to submit a form using <kbd>⏎</kbd> (Return/Enter) while still focused on a field, since it’s quicker than tabbing to and pressing the Submit button.</p>
<p>For general browsing, I like to use <kbd>Space</kbd> to scroll the page down by a viewport’s-height. I also have a habit of using the <kbd>⇥</kbd> key to move focus to links or buttons, lazily <a href="/blog/focus-priming">priming my focus</a> with the mouse/trackpad and tabbing around from there, and I’ll happily arrow around <a href="/blog/how-button-groups-should-work-for-keyboard-users">tabs and other button groups</a>.</p>
<p><i>Note: if you’re a Safari-on-Mac user and want to make more use of the keyboard <a href="/blog/how-to-use-the-keyboard-to-navigate-on-safari">there’s a bit of config</a> you have to set first.</i></p>
<h3 id="app-and-operating-system-navigation">App and operating system navigation</h3>
<p>Regardless of whether I’m typing or clicking around, my left hand is always on my keyboard, as it makes getting around my operating system much quicker; for example, I:</p>
<ul>
<li>make heavy use of <kbd>⌘</kbd> (Command) + <kbd>⇥</kbd> to switch from app to app</li>
<li>close windows with <kbd>⌘</kbd> + <kbd>w</kbd></li>
<li>open tabs with <kbd>⌘</kbd> + <kbd>t</kbd></li>
<li>go to the next or previous tab with <kbd>⌃</kbd> (Control) + <kbd>⇥</kbd> or <kbd>⌃</kbd> + <kbd>⇧</kbd> (Shift) + <kbd>⇥</kbd></li>
<li>cycle through windows with <kbd>⌘</kbd> + <kbd>`</kbd></li>
<li>quit an app with <kbd>⌘</kbd> + <kbd>q</kbd></li>
<li>press <kbd>⏎</kbd> to confirm a dialog</li>
</ul>
<p>You get the idea.</p>
<h3 id="and-an-uncommon-set-up">And an uncommon set-up</h3>
<p>Every laptop or desktop computer comes equipped with a keyboard, and keyboards are getting more and more common on iPads, but not on phones, surely?</p>
<p>You might find this bizarre, but my keyboard usage extends to my iPhone too, where I sometimes <a href="/blog/holidays-no-laptop-and-a-bluetooth-keyboard">hook a Bluetooth keyboard up to my phone</a>.</p>
<h2 id="hurdles">Hurdles</h2>
<p>Being a hybrid mouse/trackpad and keyboard user, I get a bit of an insight into some of the issues keyboard-only users encounter. Those hurdles irritate me as they break my flow and force me to use a mouse-based workaround, but there’s an extra level of frustration in knowing these are hurdles some people simply can’t get past.</p>
<p>But that’s not the full picture. People use digital products in all sorts of ways, and we’ve only just scratched the surface.</p>
<h2 id="the-wider-perspective">The wider perspective</h2>
<p>I love this micro-site on how <a href="https://how-many.herokuapp.com/people/100">100 people who use your website might break down</a>; there are people in that list whose primary input modality might be:</p>
<ul>
<li>keyboard-only</li>
<li>screen reader</li>
<li>speech recognition software</li>
</ul>
<p>Or any number of other methods, like a switch device, eye tracking, or head-wand. The point is, as my late father-in-law used to say:</p>
<blockquote lang="es-es">
    El mundo es plural
</blockquote>
<p>Which very roughly translates from Spanish as “Everybody is different”.</p>
<p>Designing and building accessible software means continually questioning your own habits and assumptions. No single way of interacting with technology is universal.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/designing-and-building-from-our-own-worldview">Designing and building from our own worldview</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Holidays, no laptop, and a Bluetooth keyboard</title>
    <link href="https://www.tempertemper.net/blog/holidays-no-laptop-and-a-bluetooth-keyboard" />
    <id>https://www.tempertemper.net/blog/holidays-no-laptop-and-a-bluetooth-keyboard</id>

    
    <published>2026-01-23T00:00:00Z</published>
    <updated>2026-01-23T00:00:06Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>In recent years I’ve tried to switch off more on holiday, so I leave my laptop at home. But I still get enjoy a bit of writing, so what to do?</summary>

    <content type="html" xml:lang="en"><![CDATA[
      <p>It has been a while since I’ve written an apropos of nothing blog post. They’re sneaky though: they actually demonstrate a point for another article I’m working on; one that’s too long to include in that post itself.</p>
<p>I used to take my laptop with me when I went on holiday. Self-employment meant I had my inbox to attend to, the occasional small job to deliver, or the odd bug to fix; I would disappear to a cafe for an hour or two each day to write some code.</p>
<p>In recent years I’ve tried to switch off more, so the laptop has stayed at home. I make sure my clients know I’m away and what to do in case of any urgent issues with their websites, and I try to check my inbox as little as possible.</p>
<p>Problem is, I’ve always enjoyed writing, so if an idea comes to mind, or an old draft crosses my thoughts, demanding I get back to it, I want to be able to do something about it. <a href="/blog/in-search-of-the-best-writing-app">I use IA Writer</a>, which is available on my iPhone, so that’s <em>something</em>, but writing an article on a phone is less than ideal.</p>
<p>I tried an iPad, since an iPad doesn’t have a decent code editor and can’t run a development environment, but writing on a software keyboard, even if it’s full-size, is arduous. I took to hooking up a Bluetooth keyboard, which was much better, then it struck me: why bother with an iPad at all!?</p>
<p>It turns out you can connect a Bluetooth keyboard to an iPhone, so now all I do is pack my Magic Keyboard in my hand luggage and I can do a bit of writing whenever the need takes me! My setup even fits nicely on aeroplane tray tables, where a laptop doesn’t quite. I do get a few funny looks from other passengers, but I can live with that.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/holidays-no-laptop-and-a-bluetooth-keyboard">Holidays, no laptop, and a Bluetooth keyboard</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>The final nail in the HTML5 document outline coffin</title>
    <link href="https://www.tempertemper.net/blog/the-final-nail-in-the-html5-document-outline-coffin" />
    <id>https://www.tempertemper.net/blog/the-final-nail-in-the-html5-document-outline-coffin</id>

    
    <published>2025-12-29T00:00:00Z</published>
    <updated>2025-12-29T00:00:07Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>All the main web browsers have finally dropped visual support for the HTML5 document outline algorithm. Here’s why that’s good news.</summary>
        <category term="Accessibility" />
        <category term="HTML" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>I’ve written about the <a href="/blog/using-the-html-document-outline">document outline</a> before, including a reference to how HTML5 introduced a new algorithm for creating a document outline which was never fully supported.</p>
<p>First, a reminder; what was the idea? Well, it was to allow content to be truly modular, so that each chunk could be included in a document wherever the author wanted without any friction:</p>
<ul>
<li>Each chunk/module/section would be wrapped in a sectioning element (like a <code>&lt;section&gt;</code>)</li>
<li>The heading level in each module would always start at level one (<code>&lt;h1&gt;</code>)</li>
<li>The browser would create the document outline based on how the modules were put together</li>
</ul>
<p>Here’s how the markup might have looked:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>This is the main heading<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>It's the level one heading.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>This is a section-scoped heading<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>It should look and behave like a level two heading.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">></span></span></code></pre>
<p>It was a neat idea, and it would have saved me a bunch of if/else logic in many of the websites I build, for example:</p>
<ul>
<li>There’s a list of blog post snippets and each has the post title as its heading</li>
<li>On the main blog listing page an <code>&lt;h1&gt;</code> introduces the page (“Blog”?) so the list item headings are level two</li>
<li>On a page like the homepage the <code>&lt;h1&gt;</code> introduces the purpose of the website and an <code>&lt;h2&gt;</code> talks about the blog; any sample posts in a short list would be level three</li>
</ul>
<p>No fiddly logic with the HTML5 document outline algorithm; the browser would take care of the levels based on how deeply they were nested.</p>
<h2 id="never-fully-supported">Never fully supported</h2>
<p>Strangely (or maybe not so strangely?) browsers added <em>some</em> support for the HTML5 document outline algorithm, but never quite finished the job:</p>
<ul>
<li>It worked <em>visually</em>, as browsers changed their default styling to match the algorithm</li>
<li>Non-visually, it did nothing; the accessibility tree just included lots of level one headings, as per the markup, so screen reader users would have been left wondering what was going on</li>
</ul>
<p>Since human beings have a tendency to view the world from their own perspective, and the majority of designers and developers are sighted, the visual conformance with the HTML5 technique was seen by many as a green light. <em>I</em> certainly saw it like that before I began to dig into accessibility and realised the problems I was causing.</p>
<h2 id="what-about-that-final-nail">What about that final nail?</h2>
<p>Firefox and Chrome removed the visual support for the HTML5 document outline algorithm some time ago:</p>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/138#experimental_web_features">Firefox in version 138, April 2025</a></li>
<li><a href="https://github.com/whatwg/html/issues/7867#issue-1218728578">Chrome around July 2025</a></li>
</ul>
<p>So I was heartened to see that the <a href="https://webkit.org/blog/17640/webkit-features-for-safari-26-2/">recent release of Safari 26.2</a> has done the same:</p>
<blockquote>
<p>To go with the intended original behavior in HTML5, the default UA styling for h1 elements was specified to visually change the headline when it was a child of article, aside, nav, or section … In Safari 26.2, following a recent HTML standard change, those UA [User Agent] styles are being removed.</p>
</blockquote>
<p>Good news.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/the-final-nail-in-the-html5-document-outline-coffin">The final nail in the HTML5 document outline coffin</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Should pagination take you to a new page?</title>
    <link href="https://www.tempertemper.net/blog/should-pagination-take-you-to-a-new-page" />
    <id>https://www.tempertemper.net/blog/should-pagination-take-you-to-a-new-page</id>

    
    <published>2025-12-03T00:00:00Z</published>
    <updated>2025-12-03T00:00:08Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>‘Pagination’ has comes from the word ‘page’, so yes, pagination should consist of pages. But the question is totally valid; worth digging into!</summary>
        <category term="Accessibility" />
        <category term="Design" />
        <category term="HTML" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>Yes. I mean, ‘pagination’ is derived from the word ‘page’. You might even wonder why this article is even necessary, but “Is pagination a new page?” is actually a reasonable question when designing with accessibility in mind. Let me explain.</p>
<h2 id="its-all-about-focus-behaviour">It’s all about focus behaviour</h2>
<p>The idea is that pagination divides a list up into pages, and it’s all housed in a <code>&lt;nav&gt;</code> (I’ve <a href="/blog/an-accessible-pagination-pattern-or-two">written about the markup elsewhere</a>), which are used to house links to other pages. Each item in a pagination group is a separate page.</p>
<p>But this comes with a downside: focus is reset to the top of the page with each press of a pagination link. That could get quite boring/arduous for a keyboard or screen reader user who would have to navigate back to the pagination to go to each subsequent page.</p>
<p>So our thoughts rightly turn towards making the experience work well for <em>everyone</em>. Two options present themselves:</p>
<ul>
<li>Keep focus where it is, allowing the user to, say, go to the seventh page, by hitting ‘Next’ several times</li>
<li>Move focus to the top of the list itself, rather than the page; saving the user having to skip past the page header and any other content that lives before the paginated list</li>
</ul>
<p>Both of these fit the <a href="/blog/buttons-links-and-focus">definition of a button</a>: they perform an action that causes a change on the page, and focus is managed carefully. Let’s explore each of those approaches.</p>
<h3 id="keeping-focus-in-place">Keeping focus in place</h3>
<p>If focus remains on the pagination button that was pressed, we have to be sure the user knows it has happened. We’d use <code>aria-live</code> to announce the change for screen reader users, but we’d have to rely on sighted users spotting that the content above the button had changed. This might be especially tricky on more constrained viewports; smaller mobile devices or when someone has increased the page zoom level.</p>
<p>But more importantly, how does the user know what page they need to be on? The journey from page 1 to page 7, to use our earlier example, would involve checking the items on each page until they find the one they’re looking for.</p>
<p>So a mouse or touch screen user would hit the ‘Next’ button, scroll to the top of the paginated area, then scroll back down again, scanning the list. A keyboard user would have to tab backwards to the start of the paginated content, then tab through it again to get to the ‘Next’ button again. Worst of all, a screen reader user would have to listen backwards through the paginated items, then listen forwards again.</p>
<p>That’s a lot of work we’d be asking people to do, when we’re looking to make things easier.</p>
<h3 id="return-focus-to-the-top-of-the-list">Return focus to the top of the list</h3>
<p>The biggest problem with the keep-focus-in-place approach is the scrolling back to the top of the list, so how about doing that bit for people? This is a reasonable approach: we place focus at the top of the list with each button press, which:</p>
<ul>
<li>Ensures sighted users know they’ve paginated</li>
<li>Saves reverse tabbing for keyboard-only users</li>
<li>Saves backwards reading for screen reader users</li>
</ul>
<p>We’d just need to add an accessible name to the element where focus lands, so that screen readers are told what ‘page’ they’re on each time.</p>
<p>This all sounds very familiar…</p>
<h3 id="overthinking-it">Overthinking it</h3>
<p>Placing focus at the beginning of the list is pretty much the sort of behaviour we’d experience if it were just a new page.</p>
<p>Instead of landing directly on the list, our <a href="/blog/focus-priming">focus would be primed</a> at the top of the page. Screen reader users would hear the page <code>&lt;title&gt;</code>, which should include the new page number, and there would be some kind of on-page indication of the new page number.</p>
<p>But there’s still all that pesky header content to get past. Luckily, we have mechanisms in place to ease the tedium:</p>
<ul>
<li>A screen reader user has a bit of an advantage here as they can use shortcut commands to navigate straight to the page’s <code>&lt;h1&gt;</code> or the <code>&lt;main&gt;</code> landmark</li>
<li>Keyboard users (and screen reader users) can use the <a href="/blog/skip-links-what-why-and-how">skip link</a> to get to the meat and potatoes of the page</li>
</ul>
<h2 id="what-else-do-we-need-to-do">What else do we need to do?</h2>
<p>So we can agree they’re pages, not pseudo-pages in a panel on the same page. Anything else is overcomplicating it. But what else is needed?</p>
<h3 id="add-the-page-number-to-the-title">Add the page number to the title</h3>
<p>Screen reader users should hear the contents of the <code>&lt;title&gt;</code> element when they arrive on a new page, reassuring them that they’ve landed on the right page.</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">></span></span>Blog page 2<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span></code></pre>
<p>This also updates the browsing history, making it easier to find the page you want to go back to.</p>
<p>No need to include any details of the page number on the first page.</p>
<h3 id="add-the-page-number-at-the-top-of-the-page">Add the page number at the top of the page</h3>
<p>Sighted users may spot the updated page number in their browser tab, where the <code>&lt;title&gt;</code> is visible, but there’s not a great deal of space up there so it’s better to give them that bit of reassurance elsewhere too.</p>
<p>It’s up to you as to <em>where</em>, but make sure it’s somewhere:</p>
<ul>
<li>after the <code>&lt;h1&gt;</code></li>
<li>before the paginated content</li>
</ul>
<p>It could even be included <em>in</em> the <code>&lt;h1&gt;</code>. On my blog, I output a paragraph just after the <code>&lt;h1&gt;</code>.</p>
<p>And, like the page title pattern, there’s no need to do this on the first page.</p>
<h2 id="some-good-advice">Some good advice</h2>
<p>I’ll finish up with a quote or two from Karl Groves’ <a href="https://afixt.com/a-quick-primer-on-accessible-pagination/">AFixt article on pagination</a>:</p>
<blockquote>
<p>Pagination typically involves navigation between different resources or views … When a button is used instead, this context is often lost or has to be artificially recreated … making the experience brittle or inconsistent.</p>
</blockquote>
<p>So yes, pagination should take you to a new page.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/should-pagination-take-you-to-a-new-page">Should pagination take you to a new page?</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>An accessible pagination pattern (or two)</title>
    <link href="https://www.tempertemper.net/blog/an-accessible-pagination-pattern-or-two" />
    <id>https://www.tempertemper.net/blog/an-accessible-pagination-pattern-or-two</id>

    
    <published>2025-11-19T00:00:00Z</published>
    <updated>2025-11-19T00:00:09Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>A couple of weeks ago I added pagination to my blog, and it was an interesting delve into the various designs and markup patterns that can be used.</summary>
        <category term="Accessibility" />
        <category term="HTML" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>At the time of writing my blog contains nearly 300 posts… As the list has grown, the footer has moved further and further out of reach, so I have finally added pagination! My pal Damien Robson got the ball rolling by raising a pull request on my <a href="https://github.com/tempertemper/www.tempertemper.net">GitHub repo</a> with the <a href="https://www.11ty.dev/docs/pagination/">core functionality</a>, and I took it from there.</p>
<p>It was an interesting delve into the various designs and markup patterns for pagination. At its simplest, pagination requires that the user:</p>
<ul>
<li>Has a mechanism to navigate from page to page</li>
<li>Understands their current position within the pages</li>
</ul>
<h2 id="a-standard-pattern">A standard pattern</h2>
<p>I remembered that the excellent Karl Groves had written <a href="https://afixt.com/a-quick-primer-on-accessible-pagination/">an article on accessible pagination</a>, so I used that as my starting reference point:</p>
<ul>
<li>Use <code>&lt;a&gt;</code> elements with <code>href</code> attributes, not <code>&lt;button&gt;</code>s</li>
<li>Add <code>aria-current=&quot;page&quot;</code> to the current page</li>
<li>Wrap it all in a <code>&lt;nav&gt;</code> element</li>
</ul>
<p>Pretty straightforward, and Karl’s example uses one of the most common patterns you’ll come across:</p>
<ol>
<li>A link to the previous page</li>
<li>Numbered links to represent each page</li>
<li>A link to the next page</li>
</ol>
<h2 id="how-i-decided-to-do-it">How I decided to do it</h2>
<p>I’ve always found the standard pagination pattern a bit too minimal. The information is all there implicitly, but you have to go through the whole component to work out where you currently sit in relation to all the pages. I decided to go with something a bit more verbose:</p>
<ol>
<li>Set the scene by telling the user which page they’re on and how many pages there are in total</li>
<li>Present links to a handful of key pages:
<ol>
<li>The first page</li>
<li>The previous page</li>
<li>The next page</li>
<li>The the last page</li>
</ol>
</li>
</ol>
<p>Here’s a simplified example of my markup:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>nav</span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pagination<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>This is page 5 of 10. Go to:<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/blog/page/1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>First<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/blog/page/4<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Previous<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/blog/page/6<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Next<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/blog/page/10<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Last<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>nav</span><span class="token punctuation">></span></span></code></pre>
<p>I added a few embellishments, such as some hidden-from-assistive-technology icons to sit next to the links, for easy visual identification:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/blog/page/1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">aria-hidden</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>⇤<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>First
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre>
<p><i>I used ‘Leftwards arrow to bar’ (<code>⇤</code>) and ‘Rightwards arrow to bar’ (<code>⇥</code>) for the first and last pages, respectively, and ‘Leftwards arrow’ (<code>←</code>) and ‘Rightwards arrow’ (<code>→</code>) for the previous and next pages.</i></p>
<h3 id="what-about-when-a-page-doesnt-exist">What about when a page doesn’t exist?</h3>
<p>If you’re on the first page, the ‘First’ and ‘Previous’ links don’t make sense, and if you’re on the last page, the ‘Next’ and ‘Last’ links don’t make sense.</p>
<p>Referring back to the <a href="https://afixt.com/a-quick-primer-on-accessible-pagination/">A Quick Primer on Accessible Pagination</a> article, Karl gives styling for <code>.page-link[aria-disabled=&quot;true&quot;]</code>, which suggests unusable links would remain on the page; this could be useful as users’ expectations of the layout pattern would remain intact. But I’m very conscious that <a href="/blog/how-to-avoid-disabled-buttons.html">disabled elements can be problematic for some people</a> as they:</p>
<ul>
<li>leave them to work out why the items are disabled and how to re-enable them</li>
<li>are usually lower-than-ideal contrast (WCAG exempts ‘inactive’ elements from <a href="https://www.w3.org/TR/wcag/#non-text-contrast">1.4.11 Non-text Contrast</a> and <a href="https://www.w3.org/TR/wcag/#contrast-minimum">1.4.3 Contrast (Minimum)</a>)</li>
</ul>
<p>For me, it’s better to remove the unusable links entirely, especially as we’re already priming the user’s expectations by telling them which page they’re on before they reach the links. For example, if they’re on page 1, they’ll know that they’re already on the first page and there’s no previous page, so there are only ‘Next’ and ‘Last’ links:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>nav</span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pagination<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>This is page 1 of 10. Go to:<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/blog/page/2<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Next<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/blog/page/10<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Last<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>nav</span><span class="token punctuation">></span></span></code></pre>
<h2 id="the-numbers-pattern-is-still-valid">The ‘numbers’ pattern is still valid</h2>
<p>I used the more wordy pattern on my blog, but I have also used the more common ‘numbers’ pattern on some <a href="/services/websites">client websites</a>.</p>
<p>Digging into the pattern, the numbered links usually work like this:</p>
<ul>
<li>The central number represents the current page</li>
<li>The link or links either side represent the page or pages prior to and following the current page</li>
<li>The first page and last page are the left- and right-most page numbers</li>
<li>There are gaps, often ellipses (<code>…</code>), between first page and the previous page(s), and the next page(s) and the last page, unless they’re sequential (for example, you’re on page 3)</li>
</ul>
<p>Here’s how it would look:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>nav</span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Pagination<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/blog/page/1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span>
    …
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/blog/page/4<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>4<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">aria-current</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>page<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>5<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/blog/page/6<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>6<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span>
    …
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/blog/page/10<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>10<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>nav</span><span class="token punctuation">></span></span></code></pre>
<p>Again, when a page isn’t available, it’s not linked to, so the first page, for example, would look like this:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>nav</span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Pagination<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">aria-current</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>page<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/blog/page/2<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>2<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span>
    …
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/blog/page/10<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>10<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>nav</span><span class="token punctuation">></span></span></code></pre>
<p>You might notice a few differences between that and the example markup pattern Karl gave.</p>
<h3 id="no-previousnext">No ‘Previous’/‘Next’</h3>
<p>I removed the ‘Previous’ and ‘Next’ page links that sat either side of the numbers. Links to these pages are already in the number sequence, so presenting them again feels superfluous.</p>
<h3 id="avoid-icon-only-links">Avoid icon-only links</h3>
<p>The ‘Previous’ and ‘Next’ page links that I removed are icons in Karl’s example. I tend to <a href="/blog/what-i-wish-was-in-wcag-prohibit-icon-only-buttons.html">avoid icons without text</a> and <a href="/blog/icon-only-links-fail-wcag.html">icon-only links</a> make me particularly uncomfortable. With them gone, I happily sidestep any icon-only controversy here!</p>
<h3 id="remove-the-link-for-the-current-page">Remove the link for the current page</h3>
<p>The current page would link to itself, which feels redundant. I made it text-only, which also makes it visually clearer that it’s not a page you need to navigate to.</p>
<p>The <code>aria-current</code> stays, of course (although <a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-current#associated_roles">I did have to check that was allowed</a> on a <code>&lt;span&gt;</code>, and it is).</p>
<h3 id="remove-navigation-from-navigation">Remove “navigation” from navigation</h3>
<p>Finally, the label for my <code>&lt;nav&gt;</code> element is just “Pagination” so that screen reader users will hear “Pagination, navigation”: the accessible name and the role. If the <code>aria-label</code> were <code>&quot;Pagination navigation&quot;</code>, it would read “Pagination navigation, navigation” in most screen reader software. Totally me just being super fussy, but anything to reduce a bit of noise.</p>
<h3 id="something-i-considered-and-dismissed">Something I considered and dismissed</h3>
<p>I did think that maybe it would be useful to add the word ‘Page’ before each number, just for screen reader users, like this:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/blog/page/10<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>visually-hidden<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Page<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span> 10
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre>
<p>But I decided against it because:</p>
<ul>
<li>Sighted users don’t get that information, so if it’s not necessary visually it shouldn’t be necessary non-visually</li>
<li>Screen reader users already get the context that this is pagination from the <code>&lt;nav&gt;</code> container and its accessible name, so hearing “page” unnecessarily before each number would be repetitive and could get annoying</li>
</ul>
<h2 id="both-patterns-have-their-place">Both patterns have their place</h2>
<p>I ended up using the more explicit pattern because it surfaces the information I care about most: where you are and what options you have next. The sleeker ‘numbers’ pattern still works well in many situations and can be a better fit when space or convention calls for something more compact. The important thing is being intentional, rather than defaulting to whichever pattern comes bundled with a framework or library.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/an-accessible-pagination-pattern-or-two">An accessible pagination pattern (or two)</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>The return of the heading group</title>
    <link href="https://www.tempertemper.net/blog/the-return-of-the-heading-group" />
    <id>https://www.tempertemper.net/blog/the-return-of-the-heading-group</id>

    
    <published>2025-11-01T00:00:00Z</published>
    <updated>2025-11-03T00:00:10Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>I’ve written about why we probably shouldn’t use header elements for headings, but what should we use instead? The &lt;hgroup&gt; element is back!</summary>
        <category term="Accessibility" />
        <category term="HTML" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>So if we <a href="/blog/page-headings-dont-belong-in-the-header">shouldn’t use headers for headings</a>, what should we use instead?</p>
<p>Well, most of the time you’ll just use the page heading (<code>&lt;h1&gt;</code>) on its own, maybe alongside a semantically neutral element like a <code>&lt;p&gt;</code> or <code>&lt;div&gt;</code>, but if the grouping of the header and its extra content is important and <em>visually</em> obvious, you may also need to communicate it non-visually. Here are some examples when you may have reached for the <code>&lt;header&gt;</code> element:</p>
<ul>
<li>To give information on the section the user is in, for example if a Team page is part of a wider ‘About’ section, that About marker could be useful</li>
<li>If your page has an alternate title, like ‘Frankenstein’ which you could couple with ‘Or: The Modern Prometheus’</li>
<li>The heading is coupled with an introductory sentence that sits outside of the main body text of the page</li>
</ul>
<p>So how do we create this association if not a <code>&lt;header&gt;</code> element? I’d go with <code>&lt;hgroup&gt;</code> (Heading Group).</p>
<h2 id="a-brief-history-of-the-heading-group-element">A brief history of the heading group element</h2>
<p>The original specification for <code>&lt;hgroup&gt;</code> was that it allowed multiple heading levels to be grouped together, and only the <a href="https://html5doctor.com/the-hgroup-element/">highest level heading</a> would contribute to the <a href="/blog/using-the-html-document-outline">document outline</a>. Here’s an example:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>hgroup</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>Dr. Strangelove<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">></span></span>Or: How I Learned to Stop Worrying and Love the Bomb<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>hgroup</span><span class="token punctuation">></span></span></code></pre>
<p>So, in theory, a screen reader user wouldn’t hear this <code>&lt;hgroup&gt;</code>'s <code>&lt;h2&gt;</code> when skipping through the headings on the page; just its <code>&lt;h1&gt;</code>. But that behaviour was never implemented by browsers, so screen reader software still picked up the <code>&lt;h2&gt;</code> just as it would any other <code>&lt;h2&gt;</code> on the page, which could lead to a slightly confusing experience, since that <code>&lt;h2&gt;</code> doesn’t represent a section of the page.</p>
<p>So <code>&lt;hgroup&gt;</code> was <a href="https://lists.w3.org/Archives/Public/public-html-admin/2013Apr/0003.html">removed from the HTML specification</a> in 2013.</p>
<p>There was still a need for some way to group headings and their directly related content, so the <a href="https://rawgit.com/w3c/subline/master/index.html"><code>&lt;subhead&gt;</code> element was explored</a> shortly afterwards:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>
    Dr. Strangelove
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>subhead</span><span class="token punctuation">></span></span>Or: How I Learned to Stop Worrying and Love the Bomb<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>subhead</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span></code></pre>
<p>The idea here was that the contents of the <code>&lt;subhead&gt;</code> would be excluded from the page outline, just as the <code>&lt;h2&gt;</code> was meant to be in our earlier example. But a new HTML element is a hard sell which is, I’m guessing, why it didn’t get much further than those early proposals.</p>
<p>The <a href="https://github.com/whatwg/html/pull/7829">the HTML spec was updated in 2022</a> (thanks for <a href="https://toot.cafe/@aardrian/115477444189108730">the link, Adrian</a>!), simultaneously resurrecting the element and fixing the document outline problem in a way that is true to the ‘pave the cowpaths’ philosophy of HTML5.</p>
<h2 id="how-it-should-work">How it should work</h2>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/hgroup">MDN Docs now has this to say</a>:</p>
<blockquote>
<p>The <code>&lt;hgroup&gt;</code> HTML element represents a heading and related content. It groups a single <code>&lt;h1&gt;</code>–<code>&lt;h6&gt;</code> element with one or more <code>&lt;p&gt;</code>.</p>
</blockquote>
<p>So no more than one heading, and the only other content we’re allowed alongside our heading is paragraphs, like this:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>hgroup</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>Dr. Strangelove<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>Or: How I Learned to Stop Worrying and Love the Bomb<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>hgroup</span><span class="token punctuation">></span></span></code></pre>
<p>This means the only thing that makes it to the document outline, of course, is the <code>&lt;h1&gt;</code>. And we have a nice way to tie other content to the heading.</p>
<h2 id="but-theres-a-catch">But there’s a catch</h2>
<p>The <code>&lt;hgroup&gt;</code> element is fine to add, but there’s an issue: browsers don’t do anything with it. At least not without a bit of extra work.</p>
<p>According to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/hgroup#technical_summary">MDN Docs’ technical summary</a>, it should get the implicit role of <code>group</code>. It does (you can see it in Chrome’s accessibility tree, for example) but, just like with <a href="https://w3c.github.io/aria/#group">ARIA’s group role</a>, nothing is actually communicated when there’s just a <code>role=&quot;group&quot;</code> attribute; you need a label in order for the role to be exposed.</p>
<h3 id="what-should-the-label-be">What should the label be?</h3>
<p>You could use <code>aria-labelledby</code> and point to the <code>&lt;h1&gt;</code>, but that would be repetitive, and all we need to convey here is that the user has reached the page’s heading group. So this wouldn’t be all that useful:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>hgroup</span> <span class="token attr-name">aria-labelledby</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>page-heading<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>page-heading<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Dr. Strangelove<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>Or: How I Learned to Stop Worrying and Love the Bomb<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>hgroup</span><span class="token punctuation">></span></span></code></pre>
<p>The markup pattern I’d recommend is <code>aria-label</code>:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>hgroup</span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Heading<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>Dr. Strangelove<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>Or: How I Learned to Stop Worrying and Love the Bomb<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>hgroup</span><span class="token punctuation">></span></span></code></pre>
<p>This exposes the <code>&lt;hgroup&gt;</code> as a “heading group”, taking the label and the role, which lets a screen reader user know where the heading group starts, its content, and where it ends.</p>
<p>“Heading” is a pretty generic label, which may work as you’d be conveying the group semantics, and that it’s a particular type of group, but it might be that you need something more specific if:</p>
<ul>
<li>You need to use multiple <code>&lt;hgroup&gt;</code> elements</li>
<li>The content itself presents an obvious, more specific accessible name</li>
</ul>
<p>Remember, you probably don’t need an <code>&lt;hgroup&gt;</code> at all, but if you have user feedback that says you do, it’s a better approach than using a <code>&lt;header&gt;</code>.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/the-return-of-the-heading-group">The return of the heading group</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>A big thank you for an incredible leaving present</title>
    <link href="https://www.tempertemper.net/blog/a-big-thank-you-for-an-incredible-leaving-present" />
    <id>https://www.tempertemper.net/blog/a-big-thank-you-for-an-incredible-leaving-present</id>

    
    <published>2025-10-20T00:00:00Z</published>
    <updated>2025-10-20T00:00:11Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>On finishing at Sage, my amazing colleagues gave me a gift that made something I’d long wanted but never quite entertained a reality. The perfect send-off.</summary>

    <content type="html" xml:lang="en"><![CDATA[
      <p>I left Sage in August after five years there. One of the first things I did was begin instilling a <a href="/portfolio/creating-a-culture-of-accessibility">culture of accessibility</a>, which meant I built relationships with lots of great people.</p>
<p>My last day was an 11-hour shift; partly to make sure I had crossed all the <code>t</code>s and dotted the <code>i</code>s, but also because of the number of people who wanted to say cheerio.</p>
<p>A close colleague, Hannah, had arranged an open video call with people from all the offices, and it was so nice to see so many familiar faces. She had also arranged a whip-round!</p>
<p>The collection was in its hundreds and I’m <em>very</em> grateful to everyone who contributed. The e-card that came alongside it was full of really lovely messages, which have taken to having a reading whenever I’m having a bit of a hard day.</p>
<p>I made sure to say thank you to everyone who had signed the card, and to let them know what I had planned with the money. My idea was to top it up slightly and get myself something I’ve wanted for over a decade but could never imagine myself buying: the <a href="https://www.lego.com/en-gb/product/millennium-falcon-75192">LEGO Millennium Falcon</a>.</p>
<p>I’m a huge Star Wars fan and the Millennium Falcon has always been my favourite ship (closely contested by Boba Fett’s space ship). I had the model when I was a boy, and when the enormous LEGO set was released it was very exciting! But I knew given price, it wasn’t something I could seriously consider spending money on, with so many higher priorities that come along with having a young family. But this was the perfect opportunity to buy something truly indulgent…</p>
<p>One person had replied to my thank-you message with this, which summed it up beautifully:</p>
<blockquote>
<p>That’s so cool that you’re going to buy the Lego Millennium Falcon kit! I hoped you’d buy something fun just for you when I threw in. It’s often rare that parents get to do that. I hope you’ll post some pics of it once you’ve got it done!</p>
</blockquote>
<p>So added a wee bit to the pot and bought the set in time for my birthday, opened it on the day, and set to work with my youngest, who loves LEGO too. We built about half of it together, which was a lot of fun, and I did the other half on my own while he was at school, which was a great way to unwind. It took just under a week to finish and it looks incredible!</p>
<img src="/assets/img/blog/millennium-falcon.jpg" alt="The LEGO Millennium Falcon with the round radar dish, on a rustic wooden table; Han Solo and Chewbacca are in the cockpit." width="800" height="450" />
<p>So thanks once again to Hannah for organising, and to <em>everyone</em> who threw a few quid in the pot. You’ve made this big kid very happy.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/a-big-thank-you-for-an-incredible-leaving-present">A big thank you for an incredible leaving present</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Headers, headings, and titles</title>
    <link href="https://www.tempertemper.net/blog/headers-headings-and-titles" />
    <id>https://www.tempertemper.net/blog/headers-headings-and-titles</id>

    
    <published>2025-10-17T00:00:00Z</published>
    <updated>2025-10-17T00:00:12Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>What we call things is important, often as it helps us communicate clearly with our team; there are three terms I regularly hear used interchangeably.</summary>
        <category term="HTML" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>What we call things is important; for all sorts of reasons but a lot of the time it’s to make communication between team members unambiguous.</p>
<p>What a designer calls something should not differ from what a developer calls it, and the easiest way to ensure this consistency is to use the terminology defined by the super smart people who wrote HTML and ARIA.</p>
<p>The <a href="https://www.w3.org/groups/wg/htmlwg/">HTML Working Group</a>, <a href="https://html.spec.whatwg.org/multipage/">HTML Living Standard</a>, and <a href="https://www.w3.org/WAI/about/groups/ariawg/">ARIA Working Group</a> spend months and years carefully defining new features (although these groups are not infallible, as the <a href="https://wiki.csswg.org/ideas/mistakes">Incomplete List of Mistakes in the Design of CSS</a> from the CSS Working Group proves).</p>
<p>Three particular terms I often hear being used interchangeably are ‘header’, ‘heading’, and ‘title’; I even catch myself doing it sometimes! Let’s have a look how they can be confused.</p>
<h2 id="header-versus-heading">Header versus heading</h2>
<p>I recently wrote about <a href="/blog/page-headings-dont-belong-in-the-header">whether headings should be in the header</a>, so let’s start with those two terms. <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/header">MDN Docs says the header</a>:</p>
<blockquote>
<p>represents introductory content, typically a group of introductory or navigational aids.</p>
</blockquote>
<p>So that’s the header strip at the top of a page. Logo, strapline, navigation, login; that kind of thing.</p>
<p>Headings, on the other hand, are the <code>&lt;h1&gt;</code> to <code>&lt;h6&gt;</code> elements, which are used to create <a href="/blog/using-the-html-document-outline">the document’s ‘outline’</a>. These can be found all over the page, not just at the start.</p>
<p>You’d be forgiven for referring to the <code>&lt;h1&gt;</code> as the ‘header’, since that is usually at the top of the page. They also both start with ‘head’. But they are two very distinct elements, and careful naming here will prevent any crossed wires.</p>
<h2 id="title-versus-heading">Title versus heading</h2>
<p>It’s a very similar story for ‘title’ and ‘heading’, where people often refer to the <code>&lt;h1&gt;</code> as the title. Going back to MDN Docs and their <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/title">description of the <code>&lt;title&gt;</code> element</a>:</p>
<blockquote>
<p>The <code>&lt;title&gt;</code> HTML element defines the document’s title that is shown in a browser’s title bar or a page’s tab</p>
</blockquote>
<p>It’s metadata that isn’t output to the page itself. It’s what you see in the browser tab for each web page, it appears in your browsing history, and search engines use it as the heading for a page in their results. The page title is also the first thing a screen reader user will hear when they arrive on a new page.</p>
<p>The main page heading is not, of course, the page title, but the content of the <code>&lt;title&gt;</code> element probably matches the <code>&lt;h1&gt;</code> pretty closely. HMRC have some really nice guidance on the <a href="https://design.tax.service.gov.uk/hmrc-design-patterns/page-title/">makeup of a page title</a>:</p>
<blockquote>
<p>The page title can have up to 4 items separated by dashes. They are:</p>
<ul>
<li>the same <code>&lt;h1&gt;</code> as the page</li>
<li>section name, which you should only include if the service has more than one section</li>
<li>service name</li>
<li>GOV.UK</li>
</ul>
</blockquote>
<p>So the main heading content is probably the first part of the page title, but they have very different uses. The <code>&lt;h1&gt;</code> describes the content on the page, where the <code>&lt;title&gt;</code> should do this as well as giving details on things like the section the page is in, the product it belongs to, and business name itself.</p>
<h2 id="title-versus-header">Title versus header</h2>
<p>This is just here for completeness, but I don’t think there’s any need to talk about using title and header interchangeably as I’ve never seen those terms confused.</p>
<h2 id="why-we-mix-them-up">Why we mix them up</h2>
<p>We muddle these terms for lots of reasons: overlapping meanings in plain English, historical habits in teams, and the blurred line between visual layout and technical specifications.</p>
<p>For me, the reason I sometimes find myself referring to the page heading as the header or title is that ‘header’ and ‘title’ are much quicker to say, where ‘heading’ needs a bit of extra definition: ‘page heading’, ‘main heading’, or maybe even ‘heading level 1’ or ‘h1’.</p>
<p>Hopefully that clarifies what each of the three are and, like me, you can catch yourself quickly if you use the wrong terminology, preventing misunderstandings within your team.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/headers-headings-and-titles">Headers, headings, and titles</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Page headings don’t belong in the header</title>
    <link href="https://www.tempertemper.net/blog/page-headings-dont-belong-in-the-header" />
    <id>https://www.tempertemper.net/blog/page-headings-dont-belong-in-the-header</id>

    
    <published>2025-10-15T00:00:00Z</published>
    <updated>2025-10-15T00:00:13Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>I have a habit of thinking pretty deeply about semantics and structure, and have been considering the main page heading and where it should live.</summary>
        <category term="Accessibility" />
        <category term="HTML" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>Unsurprisingly, I have a tendency to think pretty deeply about semantics and structure. Recently, I’ve been considering <code>&lt;h1&gt;</code> elements and where they live in the document, and I’ve landed on keeping it outside the header.</p>
<p>Don’t get me wrong, nesting the <code>&lt;h1&gt;</code> inside the page’s <code>&lt;header&gt;</code> (or <code>&lt;div role=&quot;banner&quot;&gt;</code>) is a perfectly valid approach; <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/header">according to MDN Docs</a> the <code>&lt;header&gt;</code> is used to wrap:</p>
<blockquote>
<p>introductory content, typically a group of introductory or navigational aids. It may contain some heading elements but also a logo, a search form, an author name, and other elements.</p>
</blockquote>
<p>But having thought about this, I don’t think headings are much use here. Let me explain why.</p>
<h2 id="where-should-the-page-heading-live">Where should the page heading live?</h2>
<p>I’ll start with where the <code>&lt;h1&gt;</code> <em>should</em> be placed, and you’ll start to see why the <code>&lt;header&gt;</code> isn’t the right location: it’s the header for the page, and the main page content should live within the <code>&lt;main&gt;</code> element.</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>header</span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!-- Header stuff --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>header</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>main</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>Page heading<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!-- Main page content --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>main</span><span class="token punctuation">></span></span></code></pre>
<h2 id="why-is-the-header-the-wrong-place">Why is the header the wrong place?</h2>
<p>First, we’re not talking about just any old <code>&lt;header&gt;</code> element, we’re talking about the main page header/banner.</p>
<h3 id="headers-in-the-main-element-lose-their-semantics">Headers in the main element lose their semantics</h3>
<p>Just like <a href="/blog/implicit-aria-landmark-roles#the-theory">when used in a <code>&lt;section&gt;</code> element</a>, <code>&lt;header&gt;</code> elements’ role of <code>banner</code> is removed by the browser when nested in a <code>&lt;main&gt;</code>. Going back to MDN Docs’ and their <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/header#usage_notes">Usage Notes</a>:</p>
<blockquote>
<p>when nested within said elements [sectioning content, <code>&lt;main&gt;</code>], it loses its landmark status</p>
</blockquote>
<p>So when a <code>&lt;header&gt;</code> is inside a <code>&lt;main&gt;</code>, it behaves like a <code>&lt;div&gt;</code>. So if we want to use a <code>&lt;header&gt;</code> to house our <code>&lt;h1&gt;</code> it would have to be outside <code>&lt;main&gt;</code> element so that it can do its job.</p>
<p>In this example, the header would carry no semantic meaning, so screen reader users would be left wondering where the main page header landmark was.</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>main</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>header</span><span class="token punctuation">></span></span>
        <span class="token comment">&lt;!-- Header stuff --></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>Page heading<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>header</span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!-- Main page content --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>main</span><span class="token punctuation">></span></span></code></pre>
<h3 id="separating-causes-skippingjumping-issues">Separating causes skipping/jumping issues</h3>
<p>If we decide to move the <code>&lt;h1&gt;</code> into the header to preserve its landmark role, another problem appears:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>header</span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!-- Header stuff --></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>Page heading<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>header</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>main</span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!-- Main page content --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>main</span><span class="token punctuation">></span></span></code></pre>
<p>Putting the <code>&lt;h1&gt;</code> in the <code>&lt;header&gt;</code> separates the heading from the main content of the page. This means:</p>
<ul>
<li>Keyboard users who use the <a href="/blog/skip-links-what-why-and-how">skip link</a> would jump down past the <code>&lt;h1&gt;</code>, which may scroll the heading out of the viewport</li>
<li>Likewise, screen reader users who use the skip link would jump past the heading, and would have to navigate backwards if they wanted to read it</li>
<li>Screen reader users who navigate by landmark to land on the <code>&lt;main&gt;</code> element would miss the <code>&lt;h1&gt;</code> and, again, have to navigate backwards to check it out</li>
</ul>
<p>None of these things are dealbreakers, and it would be a <a href="/blog/erring-on-the-side-of-caution">seriously tough accessibility auditor</a> who failed it against the Web Content Accessibility Guidelines (WCAG)'s <a href="https://www.w3.org/TR/wcag/#focus-order">2.4.3 Focus Order</a> since:</p>
<ul>
<li>Keyboard users will have probably seen the <code>&lt;h1&gt;</code> before they use the skip link and jump past it</li>
<li>Screen reader users will probably have heard the <code>&lt;h1&gt;</code> content via the <code>&lt;title&gt;</code> when they first landed on the page (assuming the <a href="https://www.w3.org/TR/wcag/#page-titled">2.4.2 Page Titled</a> has been met)</li>
</ul>
<p>You could even fix things for keyboard users by having the skip link jump to the <code>&lt;h1&gt;</code> rather than the <code>&lt;main&gt;</code> element. But as with many work-arounds, this could create some potential issues for screen reader users who might use the skip link:</p>
<ul>
<li>Referring to “main content” in the skip link is pretty standard, but if it says “main” and the element linked to is a heading, that could be slightly disorienting</li>
<li>Omitting “main” and using just “Skip to content” could work, but landmarks that shouldn’t be in the <code>&lt;main&gt;</code>, like the <a href="/blog/years-in-the-accessibility-learning-curve-continues"><code>&lt;aside&gt;</code> element</a> and <code>&lt;footer&gt;</code> contain content too, so the skip link text becomes less than accurate</li>
</ul>
<p>I’m really nit-picking here, but it’s important to think about things beyond the visually obvious.</p>
<h3 id="adds-noise-for-screen-reader-users">Adds noise for screen reader users</h3>
<p>A screen reader user who uses a gesture or <a href="/blog/getting-started-with-voiceover-on-macos#navigation-commands-to-get-started">keyboard shortcut to jump to the first heading</a> would hear some unnecessary information. After the details of the page heading they’ve successfully landed on, they’d then have to listen to the end of the <code>&lt;header&gt;</code> element (“End of banner” or similar) and the start of the <code>&lt;main&gt;</code> element before they got to the first bit of content after the heading.</p>
<p>Not a huge issue, but I’m all for streamlining the user experience.</p>
<h2 id="see-what-i-mean">See what I mean?</h2>
<p>I prefer to keep things simple and predictable from the user’s point of view. Page structure depends on context, but as a rule of thumb I keep the page’s <code>&lt;h1&gt;</code> out of the <code>&lt;header&gt;</code>. It keeps the hierarchy clear, the landmarks consistent, and the experience smoother for everyone.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/page-headings-dont-belong-in-the-header">Page headings don’t belong in the header</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>A new MacBook for a new chapter</title>
    <link href="https://www.tempertemper.net/blog/a-new-macbook-for-a-new-chapter" />
    <id>https://www.tempertemper.net/blog/a-new-macbook-for-a-new-chapter</id>

    
    <published>2025-09-15T00:00:00Z</published>
    <updated>2025-09-15T00:00:14Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Returning to self-employment meant buying a new laptop; here’s how I weighed up the Air versus the Pro, size, power, price, ports, and colour!</summary>
        <category term="Apple" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>The last laptop I bought was a Space Grey 13 inch MacBook Pro back in 2017. I got a pretty beefed up model, in terms of its internal specifications, and it’s still creaking along to this day (although Apple had to change that awful keyboard twice but keys continue to stick and it’s generally horrible to type on).</p>
<p>But I haven’t used it for anything serious like work for a long time. For the last five years I’ve instead relied on work laptops, but now that I’m <a href="/approaches/consultancy">self employed again</a> I found myself on Apple’s website, weighing up the pros and cons of various machines.</p>
<h2 id="form-factor">Form factor</h2>
<p>First up, it was always going to be a MacBook: I have a <a href="https://www.apple.com/uk/studio-display/">Studio Display</a> on the standing desk in my home office which I normally work from, but I’m writing this from the dining room table, and I often work from a coffee shop or shared workspace.</p>
<p>Because I like to be mobile, I also wanted the smaller size (13 inches for the Air, 14 for the Pro) as I’ve had a larger laptop in the past (a 16 inch Pro) and it was heavy, too big for train and aeroplane tray tables, and I never really felt like I <em>needed</em> that extra screen space.</p>
<h2 id="pro-or-air">Pro or Air</h2>
<p>So the next question was: Pro or Air. Aside from my very first Mac (which I’ll tell you about later), I’ve always used Pros, but the M-series Airs are pretty hard to ignore.</p>
<p>In terms of what I do, there’s not much that’s super intensive. The only thing that ever set off the fans on my last work machine (a MacBook Pro with M2 Pro chip) was batch image compression, and that usually just meant a quick tea break until it was finished. The Airs don’t have fans, which means they slow down instead, but I figured I could deal with that throttling on the odd occasion I asked a lot of it. The Air was very much in contention.</p>
<h3 id="price">Price</h3>
<p>The first thing I did was price each machine up:</p>
<ul>
<li>A top-spec M4 Air with 32GB RAM, 512GB storage, 10-core CPU, 10-core GPU, and 16-core Neural Engine came out at £1,599</li>
<li>An equivalent spec M4 Pro came out at £2,000, but the Pros can have Nano-texture displays, which I’d regret not adding, so make it £2,149</li>
</ul>
<p>That’s a £550 difference, so what would I get for that, aside from the Nano-texture:</p>
<ul>
<li>1 inch bigger screen</li>
<li>A slightly nicer display</li>
<li>An SD card slot</li>
<li>An HDMI port</li>
<li>USB-C ports on both sides of the laptop</li>
</ul>
<h3 id="screen">Screen</h3>
<p>The screen size and quality didn’t bother me at all. Just the Nano-texture; as tempting as it was, I figured: it’s a laptop; I can move it slightly or shift position if any glare is bothering me.</p>
<h3 id="ports">Ports</h3>
<p>I have loads of <a href="https://en.wikipedia.org/wiki/Dongle">dongles</a> from the years using my 2017 MacBook, which only had USB-C ports; I spent hundreds of pounds on them. So on the rare occasion where I ever want to plug an SD card in, I can use the dongle.</p>
<p>On the HDMI front, every time I’ve needed to connect to an external display in recent years, there has been a USB-C option. For projectors, HDMI is still around, but I have a dongle!</p>
<p>My biggest issue with my M2 Pro was connecting to my Studio Display. My Thunderbolt cable dangled down on the right side of the laptop, and every time I went to plug in I’d find the SD card slot first. Every. Single. Time. To find the USB-C port, I’d have to bend down under the desk to visually identify it. I wouldn’t miss that SD slot, even if it meant I didn’t have any ports at all on the right side.</p>
<h3 id="colours">Colours</h3>
<p>My first Mac was a <a href="https://en.wikipedia.org/wiki/MacBook_(2006%E2%80%932012)">white polycarbonate model</a> back in, I think, early 2009. They had discontinued the black version the year before and, while I liked my white one a lot, I would have been all over the black one.</p>
<p>Just like with my phones, I’ve always chosen the darkest model which was, until very recently, Space Grey.</p>
<p>The Pros now come in Space Black, and the Airs in Midnight. Both are nice, but Midnight is darker and a more interesting colour. More points for the Air.</p>
<h3 id="size">Size</h3>
<p>Although the 14 inch Pro isn’t large, per se, it’s thicker than the previous Pro model. The new Airs are around the same thickness as my 2017 Pro, and slightly smaller corner-to-corner, so the Air edges the Pro here yet again.</p>
<h3 id="power">Power</h3>
<p>The Air maxed out at the specifications I listed above (although I could have got a bigger hard drive, I suppose), but the Pro has much, much more headroom. It can be beefed up to around the £5k mark, but that’s way beyond anything I’d ever need. But would the maxed-out Air specs be enough?</p>
<h2 id="can-you-guess-what-i-bought">Can you guess what I bought?</h2>
<p>The maxed-out Air felt like it’d be fast enough. I bought it during my notice period, so I still had my decent-spec M2 machine for some side-by-side comparisons. The Air was <em>miles</em> faster, which I hadn’t anticipated.</p>
<p>Paying over £500 for a Pro just for the Nano-texture display would have been a step too far, especially with all the other little up-sides of the Air.</p>
<p>I’m very happy with my new MacBook Air.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/a-new-macbook-for-a-new-chapter">A new MacBook for a new chapter</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Focus on the people that make things happen</title>
    <link href="https://www.tempertemper.net/blog/focus-on-the-people-that-make-things-happen" />
    <id>https://www.tempertemper.net/blog/focus-on-the-people-that-make-things-happen</id>

    
    <published>2025-08-31T00:00:00Z</published>
    <updated>2025-08-31T00:00:15Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Accessibility buy-in from senior leadership can be tough; real change comes from the people who design and build.</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>I’ve written about how, in my half-decade at one of the UK’s biggest tech companies, I approached <a href="/portfolio/creating-a-culture-of-accessibility">creating a culture of accessibility</a>. Broadly speaking, there are two ways to do it:</p>
<ol>
<li>Top-down</li>
<li>Bottom-up</li>
</ol>
<p>Both are important, but one is vital.</p>
<h2 id="top-down-approach">Top-down approach</h2>
<p>Getting buy-in and agreement from the top sounds like the easiest approach since there are far fewer people ‘up there’ in the most senior levels of company leadership (executives, EVPs).</p>
<p>You may be lucky and have a strong ally at board level, but if not it is very, very tough. Reaching them through layers of middle management and getting past gatekeepers is a job, and once you have their attention, their time and patience are limited. They respond well to numbers and clear risk, but this is not always easy, especially in the UK and Europe where example <a href="/blog/making-sense-of-accessibility-and-the-law#you-can-be-sued">landmark court cases are few and far between</a>.</p>
<p>It takes time and tactics to work on executives, especially in larger organisations; particularly now, with AI dominating executive priorities.</p>
<h2 id="bottom-up-approach">Bottom-up approach</h2>
<p>While you’re working on the execs, your day-to-day focus should be on the people ‘on the ground’ who are doing the actual designing and building.</p>
<p>This pool of people is much, much bigger so the number of people with enthusiasm for accessibility will be high. Of course each person’s ‘clout’ is less than those at the top but there is strength in numbers.</p>
<p>One quote that has always stayed with me is from Mike Monteiro in his talk <a href="youtu.be/J0ucEt-La9w">How Designers Destroyed the World</a>:</p>
<blockquote>
<p>Every time you make a conscious choice … rather than just letting things happen or accepting what is handed to you by others … you are fulfilling your responsibility</p>
</blockquote>
<p>If you don’t think you’ve got the power to make your product more accessible, channel your inner Mike Monteiro and know you can make a difference:</p>
<ul>
<li>Researchers can push for a more representative, inclusive panel of users to test with</li>
<li>Designers can <a href="/blog/are-you-sure-that-table-isnt-a-list">consider the components and patterns they reach for</a> from a different perspective to their own</li>
<li>Developers can really <a href="/category/html">dig into HTML</a> and ARIA to ensure they’re writing accessible code, as well as get a feel for <a href="/blog/how-navigation-should-work-for-keyboard-users">keyboard-only usage</a> and <a href="/blog/getting-started-with-voiceover-on-macos">screen reader software</a></li>
<li>Testers can put pressure on their product owner to fix accessibility issues before considering work ‘done’, and for issues found in existing UI, raise bugs and push to get them fixed</li>
</ul>
<p>Enthusiasm, advocacy, and knowledge sharing gradually spread upwards through product owners and product managers, until senior management has no option but to fall in line with what’s happening on the front lines.</p>
<p>Buy-in from the top makes things easier, but isn’t a prerequisite for building accessible digital products. The people who <em>do</em> are the ones that make the difference.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/focus-on-the-people-that-make-things-happen">Focus on the people that make things happen</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Making sense of accessibility and the law</title>
    <link href="https://www.tempertemper.net/blog/making-sense-of-accessibility-and-the-law" />
    <id>https://www.tempertemper.net/blog/making-sense-of-accessibility-and-the-law</id>

    
    <published>2025-07-19T00:00:00Z</published>
    <updated>2025-07-19T00:00:16Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Accessibility isn’t just the right thing to do, it’s the law. Here’s how the law applies to digital products, in plain English.</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>The reason to make things accessible to as many people as possible is because it’s the <em>right thing to do</em>, but the sad fact is that that’s rarely how it works.</p>
<p>Where other constraints in product design, like security, are seen as non-negotiables, accessibility is often overlooked as an inconvenient nice-to-have. It often comes as a shock to product managers when the penny drops that accessibility is a legal requirement. Not only have they been exposing their product to huge risk, but they now have to re-do a lot of work, sometimes having to put feature development on hold.</p>
<p>The legal landscape is difficult to wrap your head around so, like my <a href="/blog/wcag-but-in-language-i-can-understand">deliberately over-simplified breakdown of the Web Content Accessibility Guidelines (WCAG)</a>, here’s how accessibility is covered by the law.</p>
<p><i>Note: I’m not a lawyer, and this is surface-level stuff intended to give you a feel for how it all slots together.</i></p>
<h2 id="lots-of-laws">Lots of laws</h2>
<p>There are countless laws that govern private sector digital accessibility across the world. Here are the heavy-hitters that I encounter regularly in my day-to-day work:</p>
<ul>
<li><a href="#european-accessibility-act-eaa">European Accessibility Act (EAA)</a></li>
<li><a href="#individual-eu-state-employment-law">Individual EU state employment law</a></li>
<li><a href="#equality-act-2010-united-kingdom">Equality Act 2010 (United Kingdom)</a></li>
<li><a href="#americans-with-disabilities-act-ada">Americans with Disabilities Act (ADA)</a></li>
</ul>
<h3 id="european-accessibility-act-eaa">European Accessibility Act (EAA)</h3>
<p><a href="https://eur-lex.europa.eu/eli/dir/2019/882/oj#tit_1">The EAA</a> is the new kid on the block, having taken effect on the 28th of June 2025. Some key points:</p>
<ul>
<li>Products already on the market on that date have until 2030 to comply</li>
<li>It applies to any business that sells into the EU, whether they’re in an EU state or not</li>
<li>It only applies to websites and apps that are for ‘consumers’, not those intended for business use</li>
<li>‘Microenterprises’, defined in Article 3 (23), are exempt</li>
</ul>
<h3 id="individual-eu-state-employment-law">Individual EU state employment law</h3>
<p>That last point in the EAA isn’t quite the get-out-of-jail-free card it seems, as business to business (B2B) software is usually covered in legislation on equal opportunity employment in individual EU states, for example:</p>
<ul>
<li>Germany’s <a href="https://www.gesetze-im-internet.de/sgb_9_2018/__164.html">Sozialgesetzbuch IX, §164</a></li>
<li>France’s <a href="https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000048589854">Code du travail, Article L5213-6</a></li>
<li>Spain’s <a href="https://www.boe.es/buscar/act.php?id=BOE-A-2013-12632#a7">Real Decreto Legislativo 1/2013, Artículo 7</a></li>
<li>Italy’s <a href="https://www.normattiva.it/uri-res/N2Ls?urn:nir:stato:legge:1999;68">Decreto Legislativo 151/2015, Legge 68</a></li>
</ul>
<h3 id="equality-act-2010-united-kingdom">Equality Act 2010 (United Kingdom)</h3>
<p>I live in the UK where we’ve had the Equality Act since 2010. It requires organisations to make sure that their services, including websites, mobile apps, and other digital platforms, are accessible to people with disabilities. <a href="https://www.legislation.gov.uk/ukpga/2010/15/section/20">Section 20 (3) says</a>:</p>
<blockquote>
<p>Where a provision, criterion or practice … puts a disabled person at a substantial disadvantage … in comparison with persons who are not disabled, [the duty is] to take such steps as it is reasonable to have to take to avoid the disadvantage.</p>
</blockquote>
<p>It doesn’t make a distinction between B2B and direct to consumer (D2C), so if you’re getting in the way of disabled people doing what they need to do using the software you produce, you’re liable.</p>
<h3 id="americans-with-disabilities-act-ada">Americans with Disabilities Act (ADA)</h3>
<p>Like the UK’s Equality Act, the ADA covers both D2C and B2B. It has been around since 1990, which pre-dates the internet, but there have been lots of lawsuits relating to websites and apps in the intervening decades.</p>
<p>Here’s what it says about D2C products in <a href="https://www.law.cornell.edu/uscode/text/42/12182">Title III, 42 U.S. Code § 12182(a)</a>:</p>
<blockquote>
<p>No individual shall be discriminated against on the basis of disability in the full and equal enjoyment of the goods, services, facilities, privileges, advantages, or accommodations of any place of public accommodation.</p>
</blockquote>
<p>And in <a href="https://www.law.cornell.edu/uscode/text/42/12112">Title I, 42 U.S.C. § 12112(a)</a> the ADA covers employee discrimination. This means that digital products people use at work must be accessible:</p>
<blockquote>
<p>No covered entity shall discriminate against a qualified individual on the basis of disability in regard … terms, conditions, and privileges of employment.</p>
</blockquote>
<h2 id="the-public-sector">The public sector</h2>
<p>An honourable mention for the public sector, which tends to have separate laws to govern its accessibility, as you’ll definitely have heard of some of these:</p>
<ul>
<li><a href="https://www.section508.gov">Section 508</a> in the US</li>
<li><a href="https://www.legislation.gov.uk/uksi/2018/952/made">The Public Sector Bodies Accessibility Regulations 2018</a> in the UK</li>
<li><a href="https://eur-lex.europa.eu/eli/dir/2016/2102/oj/eng">Directive (EU) 2016/2102</a></li>
</ul>
<p>But if you’re not a government organisation, you’ll be more interested in complying with the EAA, ADA, etc.</p>
<h2 id="you-can-be-sued">You can be sued!</h2>
<p>So accessibility is the law, but who has actually been sued!? Well, it turns out, lots of companies; here are some high profile examples from the United States where <em>thousands</em> of accessibility lawsuits are filed every year:</p>
<ul>
<li><a href="https://en.wikipedia.org/wiki/National_Federation_of_the_Blind_v._Target_Corp">Target (2006)</a>; this was the first major web accessibility lawsuit and defined a website as a “place of public accommodation”</li>
<li><a href="https://www.boia.org/blog/the-robles-v.-dominos-settlement-and-why-it-matters">Domino’s Pizza (2019)</a>; the Supreme Court denied review, which reinforced the 2006 application of the ADA to digital services</li>
<li><a href="https://dredf.org/nad-v-netflix/">Netflix (2012)</a>; the first online-only product to be held accountable</li>
</ul>
<p>In the UK and Europe, court cases are culturally much less common; the very real threat of legal action is usually avoided as companies are put under pressure by bodies like the <a href="https://www.rnib.org.uk">RNIB</a> and usually fix issues before being dragged through the courts in a case they are likely to lose.</p>
<h2 id="how-to-comply">How to comply</h2>
<p>If your product is in a tricky spot, accessibility-wise, you could well be in for a lot of bad PR and legal action; how do you put things right?</p>
<p>Meeting <a href="https://www.w3.org/TR/WCAG/">WCAG</a> version 2.2 level AA is a solid baseline for accessibility in the UK and US. In Europe, <a href="https://www.etsi.org/deliver/etsi_en/301500_301599/301549/03.02.01_60/en_301549v030201p.pdf">EN 301 549</a> has long been the standard, and the good news is that it’s pretty much just WCAG with a few extras, such as ensuring operating systems (like <a href="/blog/dark-mode-websites-on-macos-mojave">Dark Mode</a>, and <a href="/blog/reducing-motion">Reduce Motion</a>) are respected.</p>
<p>But meeting WCAG/EN 301 549 may still not be enough to avoid legal trouble. <a href="/blog/erring-on-the-side-of-caution">WCAG is notoriously open to interpretation</a> and even an objectively <a href="/blog/accessibility-doesnt-stop-at-wcag-compliance">conformant website or app can still create barriers</a>; for example, through confusing user journeys.</p>
<p>WCAG is a great first milestone on the way towards accessibility, but a culture of accessible product design and development is the best way to avoid legal issues.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/making-sense-of-accessibility-and-the-law">Making sense of accessibility and the law</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Hierarchy in tables</title>
    <link href="https://www.tempertemper.net/blog/hierarchy-in-tables" />
    <id>https://www.tempertemper.net/blog/hierarchy-in-tables</id>

    
    <published>2025-07-02T00:00:00Z</published>
    <updated>2025-07-02T00:00:17Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Hierarchical tables can be a lot to understand, particularly for screen reader users. Here’s how to tackle hierarchy when it can’t be avoided.</summary>
        <category term="Accessibility" />
        <category term="Development" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>Over the last five years working at an accounting and HR software company, I’ve seen a lot of <a href="/blog/are-you-sure-that-table-isnt-a-list">tables that should be lists</a>, but there are still a lot of tables that absolutely should be tables.</p>
<p>Like most older (and many newer) software companies, accessibility was never really a consideration, so the way tables were put together was often very dense, with lots of hierarchy and clickable elements. Although they’re linked, those things are better tackled individually, so I’ll start with hierarchy.</p>
<h2 id="the-rules-of-play">The rules of play</h2>
<p>There are a few things we need to be careful of when introducing parent-child relationships into a table of data. Visually, most of the hierarchical tables I’ve seen make at least some sense and, where they don’t, the ‘sell’ on making them understandable is more straightforward as it’s more of a general user experience problem which is easier to get sign off to tackle. So we’re talking about beyond the visual here; specifically screen reader users.</p>
<h3 id="info-and-relationships">Info and relationships</h3>
<p>The first pitfall is covered by the Web Content Accessibility Guidelines (WCAG), so it’s relatively easy to enforce. We need to ensure the information about hierarchical information is conveyed programmatically in order to avoid a failure of <a href="https://www.w3.org/TR/WCAG/#info-and-relationships">1.3.1 Info and Relationships</a>.</p>
<h3 id="cognitive-load">Cognitive load</h3>
<p>The other consideration is more difficult to define as it is more about the <em>user experience of screen reader users</em>. If more than a simple table of data is being presented, people using screen readers have more information to keep in working memory in order to understand their position in the hierarchy. It’s our job not to overface our users.</p>
<h3 id="an-enforced-constraint">An enforced constraint</h3>
<p>My first instinct is to simplify, so I’d always explore ways to remove hierarchy from a table altogether, breaking the data down somehow, whether:</p>
<ul>
<li>Multiple tables on the same page, separated by headings; the headings would provide the information on hierarchy</li>
<li>Multiple tables on separate pages, with a link on parent rows to ‘drill down’ into the next level of the hierarchy</li>
</ul>
<p>But let’s pretend we can’t do that, and the hierarchical data <em>must</em> be displayed in a single table.</p>
<h2 id="conveying-information-about-hierarchy">Conveying information about hierarchy</h2>
<p>If I’m looking at a table that contains hierarchy, I should be able to distinguish the child content, so I’d maybe expect it to be indented; a bit like a nested list. I might even highlight the parent content somehow (bold text?), but that’s probably less important (remember, our parent rows aren’t clickable – that’s a separate article for another day).</p>
<p>The challenge is how to convey information about a table’s hierarchy programmatically. Focusing on the child content, I want the same kind of information that’s there visually via the indent to be communicated to screen reader users. So If I land on the indented first column in a child row, I’d want to hear something like:</p>
<ol>
<li>Contents of current table cell</li>
<li>‘Joining’ text (something like “child of” or “belonging to”)</li>
<li>Name of parent cell, to give context</li>
</ol>
<p>The reverse would also work:</p>
<ol>
<li>Name of parent cell</li>
<li>Joining text</li>
<li>Contents of current table cell</li>
</ol>
<h3 id="aria">ARIA</h3>
<p>It’s <a href="https://www.w3.org/TR/using-aria/#rule1">not the first thing you should reach for</a>, but ARIA was where my mind went to and (spoiler alert!) none of the approaches work reliably across screen reader software, so I thought I’d get it out of the way.</p>
<h4 id="aria-labelledby"><code>aria-labelledby</code></h4>
<p>The <a href="https://w3c.github.io/aria/#aria-labelledby">spec doesn’t prohibit <code>aria-labelledby</code> use on a <code>&lt;td&gt;</code></a> so I started there. Here’s an example of a leaderboard where both the teams’ scores and the team members’ scores are logged:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>joiningText<span class="token punctuation">"</span></span> <span class="token attr-name">hidden</span><span class="token punctuation">></span></span> belonging to <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>table</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>caption</span><span class="token punctuation">></span></span>Pokémon league<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>caption</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>thead</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tr</span><span class="token punctuation">></span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">></span></span>Name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">></span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">></span></span>Battles<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">></span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">></span></span>Won<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">></span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">></span></span>Lost<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">></span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">></span></span>Points<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tr</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>thead</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tr</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>parent<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span> <span class="token attr-name">scope</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>rocket<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Team Rocket<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">></span></span>24<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">></span></span>0<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">></span></span>24<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">></span></span>0<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tr</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tr</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>child<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span> <span class="token attr-name">scope</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>jessie<span class="token punctuation">"</span></span> <span class="token attr-name">aria-labelledby</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>jessie joiningText rocket<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Jessie<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">></span></span>8<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">></span></span>0<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">></span></span>8<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">></span></span>0<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tr</span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!-- More Team Rocket members, then more teams with their members --></span></code></pre>
<p><code>aria-labelledby</code> allows you to refer to the <code>id</code> of the element you’re on, so by combining the current cell, the joiner text, and the parent cell I’d expect it to read something like this:</p>
<blockquote>
<p>Row 3 of 12 Name, Jessie belonging to Team Rocket, Column 1 of 5</p>
</blockquote>
<p>And it does. But only on VoiceOver and JAWS; not on NVDA. So it’s a no-go.</p>
<p><i>Note: I only tested with these three screen readers as they gave me all the info I needed to make a decision.</i></p>
<h4 id="aria-label"><code>aria-label</code></h4>
<p>I then tried the same sort of labelling with <code>aria-label</code> instead:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span> <span class="token attr-name">scope</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>jessie<span class="token punctuation">"</span></span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Jessie belonging to Team Rocket<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Jessie<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">></span></span></code></pre>
<p>Exactly the same results: fine on VoiceOver and JAWS but no dice with NVDA.</p>
<h4 id="aria-describedby"><code>aria-describedby</code></h4>
<p><code>aria-describedby</code> wouldn’t change the label, but it would, at least in theory, add the information that you’re hearing the data of a child element. So here’s the code:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span> <span class="token attr-name">scope</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>jessie<span class="token punctuation">"</span></span> <span class="token attr-name">aria-describedby</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>joiningText rocket<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Jessie<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">></span></span></code></pre>
<p>There was a problem with VoiceOver as it didn’t read the <code>hidden</code> joining text before the table, like it did with the <code>aria-labelledby</code> approach, but there was an even bigger problem with JAWS and NVDA as it didn’t work at all!</p>
<h3 id="html">HTML</h3>
<p>ARIA wasn’t the answer, so perhaps HTML would be?</p>
<h4 id="headers-attribute"><code>headers</code> attribute</h4>
<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/td#headers"><code>headers</code> attribute</a> seemed like cleanest way to do this as, similar to the <code>aria-labelledby</code> method:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span> <span class="token attr-name">scope</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>jessie<span class="token punctuation">"</span></span> <span class="token attr-name">headers</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>jessie joiningText rocket<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Jessie<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">></span></span></code></pre>
<p>It <em>almost</em> works in VoiceOver but it doesn’t read the <code>hidden</code> joining text, probably because it’s hidden from assistive technology (although that didn’t stop <code>aria-labelledby</code>), or perhaps because <code>headers</code> can only reference <code>&lt;th&gt;</code> elements. Either way, there’s a gap between the first and third references which doesn’t communicate the hierarchy clearly enough:</p>
<blockquote>
<p>Row 3 of 12 Name, and Team Rocket, Jessie, Column 1 of 5</p>
</blockquote>
<p>But that’s the least of our worries! As with <code>aria-labelledby</code>, it doesn’t work at all in either JAWS or NVDA. In the bin.</p>
<h4 id="visually-hidden-text">Visually hidden text</h4>
<p>So far no dice, so there’s only one thing for it! Clunky and inelegant but <em>reliable</em> visually hidden text. So this would be the HTML:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span> <span class="token attr-name">scope</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Jessie<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>visually-hidden<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> belonging to Team Rocket<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">></span></span></code></pre>
<p>And the CSS we’re calling would look like this:</p>
<pre class="language-css" tabindex="0"><code class="language-css"><span class="token selector">.visually-hidden</span> <span class="token punctuation">{</span>
  <span class="token property">clip-path</span><span class="token punctuation">:</span> <span class="token function">inset</span><span class="token punctuation">(</span>50%<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">height</span><span class="token punctuation">:</span> 1px<span class="token punctuation">;</span>
  <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span>
  <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span>
  <span class="token property">white-space</span><span class="token punctuation">:</span> nowrap<span class="token punctuation">;</span>
  <span class="token property">width</span><span class="token punctuation">:</span> 1px<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>As expected, this worked reliably across all the screen readers I tested with.</p>
<h2 id="keeping-cognitive-load-light">Keeping cognitive load light</h2>
<p>We have our technique, but the <em>real</em> problem with all of this is cognitive load. A table with hierarchy can relatively easy to understand visually, but non-visually there’s a lot of information from the markup to keep in <a href="https://en.wikipedia.org/wiki/Random-access_memory">RAM</a>. The user is there to look up or compare data, and <em>that’s</em> where their energy should be spent; not on working out where in the table they are and how many levels deep.</p>
<p>That brings up another issue: how many levels of hierarchy are too many? There’s no hard and fast rule as it very much depends on the content:</p>
<ul>
<li>Number of columns</li>
<li>Number of row</li>
<li>Complexity of data</li>
<li>Variety of data types</li>
</ul>
<p>Introducing any hierarchy at all already feels like it could compromise screen reader users’ experience, but anything other than simple data is going to start feeling overwhelming.</p>
<p>If a complex hierarchical table can be broken down into several more digestible tables, that’s what should be done. If it’s <em>absolutely unavoidable</em> to use hierarchy in a table, it should be done with caution.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/hierarchy-in-tables">Hierarchy in tables</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Everything has its time</title>
    <link href="https://www.tempertemper.net/blog/everything-has-its-time" />
    <id>https://www.tempertemper.net/blog/everything-has-its-time</id>

    
    <published>2025-07-01T00:00:00Z</published>
    <updated>2025-07-01T00:00:18Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>I’ve recently decided to move on from my position at Sage and it has got me thinking about how things have a natural arc.</summary>

    <content type="html" xml:lang="en"><![CDATA[
      <p>It’s a shame when things come to an end. I’ve recently decided to move on from my position at Sage after five years and it has got me thinking about a lot of things, including how things have a natural arc.</p>
<p>I’ve been reviewing the <a href="/skills/">Skills section</a> of my website, which I had forgotten was there, and one of the pages was on a little content management system (CMS) called Perch.</p>
<p>Perch was brilliant. I read about it in <a href="https://www.creativebloq.com/net-magazine">Net Magazine</a> back in 2010, when searching for a WordPress alternative (me and WordPress have never seen eye to eye!), and it made perfect sense to me:</p>
<ul>
<li>The editing experience was well designed and made perfect sense to my clients, who had little/no technicnical know-how</li>
<li>It focused on structured content rather than a giant <a href="https://en.wikipedia.org/wiki/WYSIWYG">WYSIWYG</a> textarea, so I could ensure editors wouldn’t accidentally break their website</li>
<li>The markup in the templates was completely unopinionated; everything as I coded it and no extraneous <code>&lt;div&gt;</code>s</li>
<li>The community was amazing, often propping up my limited <a href="https://www.php.net/">PHP</a> expertise</li>
</ul>
<p>But all good things come to an end. Releases had been few and far between for a couple of years and <a href="https://community.perchcms.com/forum/thread/3289-perch-has-a-new-home/">Perch was sold in 2021</a>. Within a year it was clear that the new owners were just looking to make what money they could out of existing customers with minimal investment.</p>
<p>So I started to move all of my clients onto a more open platform: <a href="https://www.11ty.dev">Eleventy</a>. For those that used their CMS functionality regularly, I plugged in <a href="https://decapcms.org">Decap CMS</a>. No database, no licenses or upgrades to purchase, but still the simplicity of editing and clean output.</p>
<p>I <em>loved</em> Perch while it was in active development, just as I’ve loved my time at Sage, but sometimes the time comes to move on. It can be sad, but the ‘what comes next’ is exciting!</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/everything-has-its-time">Everything has its time</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Erring on the side of caution</title>
    <link href="https://www.tempertemper.net/blog/erring-on-the-side-of-caution" />
    <id>https://www.tempertemper.net/blog/erring-on-the-side-of-caution</id>

    
    <published>2025-06-21T00:00:00Z</published>
    <updated>2025-06-21T00:00:19Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>At some point a third party will audit the accessibility of your product; being strict now makes that process smoother and far less stressful.</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>The organisation I’m currently working in has <em>lots</em> of digital products, many of which have some form of integration with UK Government services (tax, payroll, etc.) and, as a result, they come under regular scrutiny by various Government departments.</p>
<p>You might be in a similar position. Maybe your product integrates into a larger software ecosystem and your contract with that company says you must be compliant with, or making progress towards, a certain level of accessibility.</p>
<p>The measure most organisations use is the Web Content Accessibility Guidelines (WCAG) version 2.1, level AA; hit this and you have a solid <a href="/blog/accessibility-doesnt-stop-at-wcag-compliance">baseline</a> accessibility.</p>
<h2 id="wcag-conformance-can-be-open-to-interpretation">WCAG conformance can be open to interpretation</h2>
<p>There are only a handful of rules (WCAG calls them ‘success criteria’, or SCs) that you can measure with a clear ‘yes’ or ‘no’. The overwhelming majority are woolly, grey, and open to interpretation.</p>
<p>Think of an SC and I bet there’s some wiggle room on what could be considered a pass or fail:</p>
<ul>
<li><a href="https://www.w3.org/TR/WCAG/#info-and-relationships">1.3.1 Info and Relationships</a>? Yep.</li>
<li><a href="https://www.w3.org/TR/WCAG/#headings-and-labels">2.4.6 Headings and Labels</a>? Absolutely.</li>
<li><a href="https://www.w3.org/TR/WCAG/#on-focus">3.2.1 On Focus</a>? You betcha.</li>
</ul>
<p>Even relatively straightforward SCs like <a href="https://www.w3.org/TR/WCAG/#non-text-content">1.1.1 Non-text Content</a> and <a href="https://www.w3.org/TR/WCAG/#focus-order">2.4.3 Focus Order</a>, can sometimes be argued one way or the other.</p>
<h2 id="some-things-come-down-to-opinion">Some things come down to opinion</h2>
<p>Granted, most things are still an obvious pass or fail, and the grey areas are often narrow, but there’s a danger there. Let’s say you audit your product and there’s a borderline issue where you could go either way; let’s say you’re feeling permissive, and you give it a ‘pass’.</p>
<p>There will come a time when you need to validate you and your team’s hard work with an objective third party accessibility audit. But it might be that their auditors are stricter, and could view that same issue you passed as a marginal fail.</p>
<h2 id="the-benefits-of-a-stricter-approach">The benefits of a stricter approach</h2>
<p>The good news is that having stricter approach to those ‘is it/isn’t it’ issues has a good number of benefits.</p>
<h3 id="fewer-awkward-conversations">Fewer awkward conversations</h3>
<p>I don’t mind a difficult conversation, but I don’t relish them. I want to avoid a situation where I might have to defend my position where I’ve been lenient and a third party auditor hasn’t.</p>
<p>The external auditor has no skin in the game, where my colleagues and I could be seen to have, so the perception is that <em>of course</em> we’d go easy on ourselves. Stakeholders may then wonder what else we’ve been happy to let slip through, which erodes their confidence and the internal accessibility team’s credibility.</p>
<h3 id="confidence">Confidence</h3>
<p>Speaking of confidence, letting fewer grey-area issues through means you can be confident in your work, regardless of how strict a third party auditor is. No need to fret when it comes to outside scrutiny.</p>
<h3 id="a-deeper-understanding">A deeper understanding</h3>
<p>When the line is drawn on the stricter side, it also means the conversation with designers and developers goes deeper, which enriches their understanding of accessibility and the various approaches they might take to overcome a potential issue for users.</p>
<h3 id="better-results-for-users">Better results for users</h3>
<p>And, of course, having a stricter position on internal accessibility has the happy effect of making the product that little bit easier for disabled people to use.</p>
<p>WCAG has its (many!) problems, but it’s the standard measure of accessibility. So when we encounter those areas where it’s open to interpretation, there are so many reasons why it’s better to err on the side of caution to ensure compliance when third party audits become part of the process.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/erring-on-the-side-of-caution">Erring on the side of caution</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>WWDC 2025 roundup</title>
    <link href="https://www.tempertemper.net/blog/wwdc-2025-roundup" />
    <id>https://www.tempertemper.net/blog/wwdc-2025-roundup</id>

    
    <published>2025-06-11T00:00:00Z</published>
    <updated>2025-06-11T00:00:20Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Apple’s World Wide Developers Conference (WWDC) opening keynote is one of the big highlights in my calendar. Here are the bits that stood out to me.</summary>
        <category term="Apple" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>You probably know by now, but Apple’s WWDC (World Wide Developers Conference) opening keynote is one of the big highlights in my calendar.</p>
<p>I love software design, and Apple do it pretty well; I also spend a <em>lot</em> of time using their software, whether on my wrist, in my hand, on my lap, or desk.</p>
<h2 id="apple-intelligence">Apple Intelligence</h2>
<p>It started with a blink-and-you’ll-miss-it explanation for the headline AI features from last year’s keynote that they didn’t deliver, citing their high quality assurance bar as the reason. Fair enough, I suppose, but it’s not like Apple to announce something that they know might not ship.</p>
<p>There was a bit more AI at this year’s event, with a nice Visual Intelligence feature via the screenshots. I’m still not all that blown away by the whole AI thing, but it’s coming in useful here and there. Maybe in time I’ll wonder how I managed without it, but that’s years off.</p>
<h2 id="liquid-glass">Liquid Glass</h2>
<p>The headline news was the new visual design language, Liquid Glass, which looks lovely but gives me <a href="https://www.theguardian.com/technology/2013/sep/27/ios-7-motion-sickness-nausea">iOS 7 vibes, in terms of its accessibility</a>, particularly from a contrast point of view with all those translucent backgrounds. I’m sure I’ll dig into that when I get the chance.</p>
<h2 id="spotlight">Spotlight</h2>
<p>A visual refresh is great, but it’s new and improved features that are the most useful; the feature that jumped out to me was Spotlight on macOS.</p>
<p>I use spotlight as my app launcher, rather than the Dock, and the extra power it’s getting will be welcome:</p>
<ul>
<li>Quick-launch looks great, so I can carry out an action like adding a to-do list item to Reminders by typing <kbd>a</kbd>, <kbd>r</kbd> (‘add reminder’)</li>
<li>It also allows you to do a bunch of things directly inside Spotlight, like typing out the reminder you’ve just quick-launched, rather than going to the Reminders app itself; a bit like Siri, only I don’t have to worry about it constantly misinterpreting my Scottish accent</li>
<li>Clipboard History looks perfect for me! I use <a href="https://tapbots.com/pastebot/">Pastebot</a> for that at the moment, but Pastebot’s other features are wasted on me so I’ll be fine with Clipboard History inside Spotlight</li>
</ul>
<h2 id="juicy-but-not-of-benefit-to-me">Juicy but not of benefit to me</h2>
<p>The changes to iPadOS are probably the most consequential of all, but only for iPad users, and I’m not one. Introducing windows brings it much closer to the Mac experience and, while I’d be interested to try it out, I often need deeper control using things like Terminal to do the work I do, so iPad would never be much more than a writing and scribbling device for me.</p>
<h2 id="features-without-fanfare">Features without fanfare</h2>
<p>There are also a handful nice features sneaking in too, which they didn’t speak about but <a href="https://mastodon.social/@tempertemper/114655124509216133">showed on a quick slide</a>:</p>
<ul>
<li>Select partial text in a bubble in Messages (finally!)</li>
<li>Custom snooze length for alarms (not just <a href="https://youtu.be/s8xTt913Lec">9 minutes</a> anymore)</li>
<li>Export notes to Markdown, which gives me yet another reason to double down on using the Notes app</li>
</ul>
<h2 id="whats-missing">What’s missing</h2>
<p>It has got to the point where there’s not much I’m really desperate for in the way of features across the Apple ecosystem. If you really pressed me, I would have liked draft messages to sync across devices. Slack does that: start writing on your phone, pick it up on your Mac (or vice versa). Only the other day I found a month-old, half-written message on my Mac that I would have noticed and sent had it had it appeared on my iPhone. But I’m not pining for that.</p>
<p>The odd thing I never knew I wanted might appear, as with <a href="https://www.tempertemper.net/blog/wwdc-2024-roundup">iPhone Mirroring last year</a>, but in general all I want year-on-year is refinement.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/wwdc-2025-roundup">WWDC 2025 roundup</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Colour alone can be used to convey meaning, and I don’t like it!</title>
    <link href="https://www.tempertemper.net/blog/colour-alone-can-be-used-to-convey-meaning-and-i-dont-like-it" />
    <id>https://www.tempertemper.net/blog/colour-alone-can-be-used-to-convey-meaning-and-i-dont-like-it</id>

    
    <published>2025-06-02T00:00:00Z</published>
    <updated>2025-06-02T00:00:21Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Despite WCAG’s guidance to avoid conveying information with colour alone, there’s a caveat that allows it, and I’m not a happy bunny!</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p><a href="https://www.w3.org/TR/WCAG/#use-of-color">1.4.1 Use of Color</a> in the Web Content Accessibility Guidelines (WCAG) seems straightforward:</p>
<blockquote>
<p>Color is not used as the only visual means of conveying information, indicating an action, prompting a response, or distinguishing a visual element.</p>
</blockquote>
<p>What that’s saying is that if we use colour on its own to convey meaning, we’re not going to meet 1.4.1. That’s not to say we can’t use colour to convey meaning at all; we just need to have an additional affordance; maybe <a href="https://wearecolorblind.com/examples/bbc-online-football-tables/">add some text</a>, maybe use an icon, maybe something else.</p>
<p>But there is an exception where colour on its own <em>can</em> be used to convey meaning. And, annoyingly, it’s buried in WCAG’s <a href="https://www.w3.org/WAI/WCAG22/Understanding/use-of-color.html">‘Understanding’ piece for 1.4.1</a>:</p>
<blockquote>
<p>If content is conveyed through the use of colors that differ not only in their hue, but that also have a significant difference in lightness, then this counts as an additional visual distinction, as long as the difference in relative luminance between the colors leads to a contrast ratio of 3:1 or greater.</p>
</blockquote>
<p>My first issue with this is that I really don’t think the accompanying Understanding documents are the place to introduce caveats; that should all be done in the main WCAG document.</p>
<p>Now that that’s off my chest, let’s have a look at what it’s saying in plain English. If the contrast ratio of the colour we’re using to convey meaning is high enough, and we don’t cause any knock-on <a href="https://www.w3.org/TR/WCAG/#contrast-minimum">1.4.3 Contrast (Minimum)</a> or <a href="https://www.w3.org/TR/WCAG/#non-text-contrast">1.4.11 Non-text Contrast</a> issues, it’s okay not to have any extra affordances.</p>
<p>So to my second issue: this, like many other WCAG exceptions, encourages designers to get lazy; just up the contrast a bit to 3:1 and we can use colour on its own to convey important information.</p>
<p>We should be aiming to make our digital products as accessible as we can and <em>just enough</em> doesn’t feel right at all.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/colour-alone-can-be-used-to-convey-meaning-and-i-dont-like-it">Colour alone can be used to convey meaning, and I don’t like it!</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Are you sure that table isn’t a list?</title>
    <link href="https://www.tempertemper.net/blog/are-you-sure-that-table-isnt-a-list" />
    <id>https://www.tempertemper.net/blog/are-you-sure-that-table-isnt-a-list</id>

    
    <published>2025-05-25T00:00:00Z</published>
    <updated>2025-05-25T00:00:22Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>We often reach for a tables when a list would be much more user friendly, and avoid potential WCAG issues.</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>I work in a software company that deals with finances, so tables are used a lot. Problem is, because they’re so commonplace, they’re often the first pattern designers reach for when another might be more appropriate: a list.</p>
<p>The thing about a table is, it’s rigid; necessarily so. All that information needs to be exactly where it is in that two-dimensional grid in order for the table to be useful for things like:</p>
<ul>
<li>Comparing data</li>
<li>Finding patterns</li>
<li>Looking for relationships</li>
</ul>
<p>But that necessary rigidity comes at a cost; it makes things a bit awkward on small screens.</p>
<p><i>Note: it’s easiest to think of viewport constraints in terms of small screens, but it could also be a larger laptop or desktop computer where the the browser zoom has been increased significantly, causing the content to take up more space within its container.</i></p>
<p>At screen sizes where the table is wider than the available space, it’s going to need to scroll horizontally, which can be an awkward experience.</p>
<h2 id="1410-reflow">1.4.10 Reflow</h2>
<p>First let’s see what the rulebook has to say about content that causes scrolling in two directions. The Web Content Accessibility Guidelines (WCAG)'s <a href="https://www.w3.org/TR/WCAG/#reflow">Reflow says this</a>:</p>
<blockquote>
<p>Content can be presented without … requiring scrolling in two dimensions for … Vertical scrolling content at a width equivalent to 320 CSS pixels.</p>
</blockquote>
<p>Websites are usually scrollable vertically (up and down), and what this is saying is that on small screens nothing should scroll horizontally as well. So content should wrap and ‘reflow’ in order to fit whatever screen size it’s being viewed on.</p>
<p>It then goes on to say:</p>
<blockquote>
<p>Except for parts of the content which require two-dimensional layout for usage or meaning.</p>
</blockquote>
<p>Fair enough; there are going to be some situations where the content can’t reflow and still make sense, and it goes on to provide a bunch of specific exceptions in Note 2:</p>
<blockquote>
<p>Examples of content which requires two-dimensional layout are images required for understanding (such as maps and diagrams), video, games, presentations, data tables (not individual cells), and interfaces where it is necessary to keep toolbars in view while manipulating content. It is acceptable to provide two-dimensional scrolling for such parts of the content.</p>
</blockquote>
<p>So WCAG is okay with data tables scrolling horizontally. This makes sense, since the point of a table is for the data to be relational and comparative.</p>
<h2 id="that-word-data">That word ‘data’</h2>
<p>Notice the wording: not “tables”; “data tables”. Let’s look at some definitions of ‘data’.</p>
<p><a href="https://www.google.com/search?client=safari&amp;rls=en&amp;q=data+dictionary+definition&amp;ie=UTF-8&amp;oe=UTF-8">Google</a> describes data as:</p>
<blockquote>
<p>facts and statistics collected together for reference or analysis.</p>
</blockquote>
<p><a href="https://www.merriam-webster.com/dictionary/data">Miriam-Webster</a> has this to say:</p>
<blockquote>
<p>factual information (such as measurements or statistics) used as a basis for reasoning, discussion, or calculation</p>
</blockquote>
<p><a href="https://dictionary.cambridge.org/dictionary/english/data">Cambridge Dictionary</a> talks about data in terms of:</p>
<blockquote>
<p>information, especially facts or numbers, collected to be examined and considered and used to help decision-making</p>
</blockquote>
<p>So WCAG’s not saying you can throw any old content in a table and it’s fine; it has to be <em>data</em>.</p>
<h2 id="using-lists-instead-sometimes">Using lists instead, sometimes</h2>
<p>So if tables aren’t always the right pattern to use, how might we use lists instead?</p>
<h3 id="description-lists">Description lists</h3>
<p>As I mention in <a href="/blog/accessible-responsive-tables">Accessible responsive tables</a>:</p>
<blockquote>
<p>One approach to tables that work on all sorts of screen sizes is to reformat the table on smaller screens. Essentially, you take each table row and repurpose it as a sort of <code>&lt;dl&gt;</code>, visually, where each row is presented as a series of keys (each table header) and a values (the value under the header).</p>
</blockquote>
<p>I think my main issue with this approach is that it’s not <a href="https://www.lukew.com/resources/mobile_first.asp">mobile first</a>. If a <code>&lt;dl&gt;</code> (<a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/dl">description list</a>) approach is the right approach on small screens, it’s probably the right approach on larger screens too.</p>
<p>Description lists offer a key/value structure. One key, one or more values for that key. So if you were listing the instruments each of The Beatles played in their early years, the markup might look like this:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>Instruments The Beatles played in their early years<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dl</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dt</span><span class="token punctuation">></span></span>John Lennon<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dt</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dd</span><span class="token punctuation">></span></span>Rhythm guitar<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dd</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dd</span><span class="token punctuation">></span></span>Harmonica<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dd</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dt</span><span class="token punctuation">></span></span>Paul McCartney<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dt</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dd</span><span class="token punctuation">></span></span>Bass guitar<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dd</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dt</span><span class="token punctuation">></span></span>George Harrison<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dt</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dd</span><span class="token punctuation">></span></span>Lead guitar<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dd</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dt</span><span class="token punctuation">></span></span>Ringo Starr<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dt</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dd</span><span class="token punctuation">></span></span>Drums<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dd</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dl</span><span class="token punctuation">></span></span></code></pre>
<p>This <em>could</em> be marked up as a table, but it works fine as a list, so a list is probably the right call here, since it offers more flexibility.</p>
<h3 id="unorderedordered-lists">Unordered/ordered lists</h3>
<p>If you need more complexity in each list item, an unordered or ordered list is worth considering.</p>
<p>Here’s a list with facts about The Beatles:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>Beatles facts<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">></span></span>John Lennon<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>John was the founding member of and a lead vocalist in The Beatles.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dl</span><span class="token punctuation">></span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dt</span><span class="token punctuation">></span></span>Instruments played<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dt</span><span class="token punctuation">></span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dd</span><span class="token punctuation">></span></span>Rhythm guitar<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dd</span><span class="token punctuation">></span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dd</span><span class="token punctuation">></span></span>Harmonica<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dd</span><span class="token punctuation">></span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dd</span><span class="token punctuation">></span></span>Piano<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dd</span><span class="token punctuation">></span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dt</span><span class="token punctuation">></span></span>Place of birth<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dt</span><span class="token punctuation">></span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dd</span><span class="token punctuation">></span></span>Liverpool<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dd</span><span class="token punctuation">></span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dt</span><span class="token punctuation">></span></span>Date of birth<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dt</span><span class="token punctuation">></span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dd</span><span class="token punctuation">></span></span>09/10/1940<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dd</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dl</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://en.wikipedia.org/wiki/John_Lennon<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Read more about John on Wikipedia<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span>.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!-- List items for the remaining three Beatles --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span></code></pre>
<p>Again, this <em>could</em> be presented as a table, but it’s not central that each bit of information is displayed relative to the others.</p>
<p>We can use <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout">CSS Grid</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout/Subgrid">Subgrid</a> to make each bit of data align with its equivalent data where space allows, which kind-of offers a table-ish visual experience, but that layout:</p>
<ul>
<li>is not vital to the understanding of the data as a whole</li>
<li>would be more for visual tidiness</li>
</ul>
<h2 id="the-question-to-ask-yourself">The question to ask yourself</h2>
<p>So, the question you should always ask yourself if you’re considering reaching for a table to present your content is: could the content also be presented in a list?</p>
<p>If the answer to this is ‘no’, then of course a table is the right element to use. If the answer is ‘yes’, in other words it could be a list <em>or</em> a table, then a list is probably the safest, most flexible pattern to reach for.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/are-you-sure-that-table-isnt-a-list">Are you sure that table isn’t a list?</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Focus priming</title>
    <link href="https://www.tempertemper.net/blog/focus-priming" />
    <id>https://www.tempertemper.net/blog/focus-priming</id>

    
    <published>2025-04-29T00:00:00Z</published>
    <updated>2025-04-29T00:00:23Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Most people won’t need to know what focus priming is but it’s a useful way to test a website’s accessibility.</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>What’s it called when you click somewhere on a webpage? Most people won’t care, either because it doesn’t seem to do anything, or they can’t click because they don’t use a mouse or trackpad.</p>
<p>But <em>I care</em> because I use it when testing the accessibility of web pages. If I click somewhere and then press <kbd>⇥</kbd> (Tab), keyboard focus is placed on the next interactive element (link, form field, etc.) after where I clicked.</p>
<h2 id="focus-start-position">Focus start position</h2>
<p>Let’s start at the start.</p>
<p>If a keyboard user presses <kbd>⇥</kbd> once a page has loaded, focus is placed on the first interactive element on the page, often a <a href="/blog/skip-links-what-why-and-how">skip link</a>. A screen reader user will hear the first bit of content on the page (again, probably/hopefully a skip link).</p>
<p>This suggests the <em>page itself</em> has focus before you move a muscle; this is your <a href="https://mastodon.social/@patrick_h_lauke/114383488828671138">focus start position</a>.</p>
<h3 id="its-invisible">It’s invisible</h3>
<p>Unlike when you focus on interactive elements, that initial focus isn’t visible. That’s okay, as the page itself:</p>
<ul>
<li>isn’t interactive</li>
<li>can’t be re-focused</li>
</ul>
<p>A visual indicator would be misleading.</p>
<h2 id="moving-focus-position-elsewhere-on-the-page">Moving focus position elsewhere on the page</h2>
<p>Thinking purely about mouse/pointer use, how do we move that initial focus position elsewhere on the page? All you have to do is click somewhere:</p>
<ul>
<li>Clicking a link will usually take your focus to a new page, but some links move your focus to a specific part of the page (I’m thinking of those skip links again, but tables of content often do the same thing)</li>
<li>Clicking a form field is an obvious way to move your focus as the form field you click will get a focus indicator.</li>
<li>Clicking a button puts focus on that button, which in turn may place focus somewhere else (<a href="/blog/buttons-links-and-focus#buttons-and-modals">like a modal</a>)</li>
<li>Click on pretty much anything else (an image, or a word in a block of text) it’ll get that same invisible focus that the page itself had</li>
</ul>
<p>The last example is the one we’re most interested in here, and it’s the one I was struggling to name. I asked around and I very much like ‘<a href="https://mastodon.social/@jtruk/114383257428586767">focus priming</a>’.</p>
<h2 id="how-to-prime-focus">How to prime focus</h2>
<p>If I want to check if something works for a screen reader user or keyboard-only user, I prime my focus by clicking my mouse pointer next to the thing I want to test.</p>
<p>I <em>could</em> use a skip link, or navigate down the page using something like my screen reader’s ‘go to next heading’ shortcut, but it’s often quicker to prime my focus using the mouse first.</p>
<h3 id="using-the-keyboard">Using the keyboard</h3>
<p>Here’s how to prime focus when testing something for keyboard-only use:</p>
<ol>
<li>Click on some text just before the interactive element you want to tab to</li>
<li>Press <kbd>⇥</kbd> to move focus onto the element</li>
</ol>
<p>Sometimes it’s necessary to tab backwards onto an element, in which case do the opposite: click just after the button/link/form field you want to give focus to, then press <kbd>⇧</kbd> (Shift) + <kbd>⇥</kbd>.</p>
<h3 id="using-a-screen-reader">Using a screen reader</h3>
<p>To test for screen reader users, <a href="/blog/screen-reader-users-and-the-tab-key">we’re not going to use the tab key</a> as it’s not just interactive elements we’re interested it; it could be a list, heading, or any other piece of static content.</p>
<p>That aside, it’s exactly the same principle:</p>
<ol>
<li>Prime focus by clicking just before the element you want to test</li>
<li>Move through the content to element you want to test (for example <a href="/blog/getting-started-with-voiceover-on-macos#navigation-commands-to-get-started">VO + <kbd>→</kbd></a>)</li>
</ol>
<p>And the same if you want to test moving back to some content: prime focus just after the content and read back through the interface.</p>
<h2 id="so-now-weve-know-what-to-call-it">So now we’ve know what to call it!</h2>
<p>Big thanks to Patrick and James for the what-do-we-call-it suggestions. Neither term clashes with already understood ideas or terminology around more obvious focus placement; nor do they require any extra explanation, as they describe both the default focus position and the act of placing focus somewhere else manually perfectly.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/focus-priming">Focus priming</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>How navigation should work for keyboard users</title>
    <link href="https://www.tempertemper.net/blog/how-navigation-should-work-for-keyboard-users" />
    <id>https://www.tempertemper.net/blog/how-navigation-should-work-for-keyboard-users</id>

    
    <published>2025-03-22T00:00:00Z</published>
    <updated>2025-03-22T00:00:24Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>The web is a network of pages that are linked together, with those links often grouped in a navigation. Here’s how keyboard users traverse navigation.</summary>
        <category term="Accessibility" />
        <category term="Development" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>Navigation is a central concept in web design, the web being a network of interconnected pages and all that. Navigation is found in a few standard places; almost always in the header of each page, sometimes in the footer, and every now and then in amongst the main page content.</p>
<p>I’ve written about <a href="/blog/how-button-groups-should-work-for-keyboard-users">how button groups work for keyboard users</a>, so in the interests of completion I thought it would be worth doing the same thing for navigation. Spoiler alert: it’s much, much simpler.</p>
<p><i>Note: although this is about keyboard users, like the article about button groups there’s example markup, and it would remiss of me not to explain how it serves screen reader users too, so you’re getting a two-for-one!</i></p>
<h2 id="an-example-of-navigation">An example of navigation</h2>
<p>Let’s start with some example markup:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>nav</span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Primary<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/home<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Home<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/about<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>About<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/contact<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Contact<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>nav</span><span class="token punctuation">></span></span></code></pre>
<p>Unlike the button group markup, I haven’t left anything out here. And there’s no fancy JavaScript needed to move focus around. Let’s pick our markup apart:</p>
<ol>
<li>First we have the <code>&lt;nav&gt;</code> wrapper which carries the implicit ‘navigation’ role so that screen reader users can use it as a landmark</li>
<li>Then we have its <code>aria-label</code>, with which we communicate the type of navigation this particular one is, in case there are multiple navigation landmarks</li>
<li>Next up an unordered list (<code>&lt;ul&gt;</code>) to tell screen reader users that they’ve encountered a list of items and how many there are; it’s unordered because the order of the items isn’t central to understanding the list</li>
<li>Then some list items themselves, each marked up with the <code>&lt;li&gt;</code> element</li>
<li>Finally, each list item contains a link to a different page on the same website, using an <code>&lt;a&gt;</code> element with an <code>href</code> attribute</li>
</ol>
<p>The thing on the end of all the navigation and list markup is a link. Navigation is all about groups of <em>links</em>, not <em>actions</em> (as that’s what button groups are for).</p>
<h2 id="sometimes-navigation-contains-buttons">Sometimes navigation contains buttons</h2>
<p>That’s not to say you’ll never see a button in navigation though. Let’s have a look:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>nav</span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Primary<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/home<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Home<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">aria-expanded</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>false<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>About<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span> <span class="token attr-name">hidden</span><span class="token punctuation">></span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/about/ethos<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Our ethos<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/about/team<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Meet the team<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/about/history<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Company history<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/contact<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Contact<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>nav</span><span class="token punctuation">></span></span></code></pre>
<p>How does that differ from our first example?</p>
<ul>
<li>The second navigation item is no longer a link to an ‘About’ page, it’s a button (the trigger for a sub-navigation) and a list (the sub-nav)</li>
<li>The button has an <code>aria-expanded</code> attribute in the <code>false</code> state, to tell screen reader users that there’s some content that will appear on press (this should be paired with a visual indicator to do the same; usually a wee downward-pointing arrow/chevron/triangle added with CSS)</li>
<li>The sub-nav has the <code>hidden</code> attribute so that it doesn’t appear on screen and isn’t available to assistive technologies like screen readers</li>
<li>The button would use some JavaScript to remove the <code>hidden</code> attribute on press, which would in turn reveal the sub-nav with its links to various pages about the company</li>
<li>When the sub-nav is opened, some JavaScript should change the <code>aria-expanded</code> value on the button from <code>false</code> to <code>true</code></li>
</ul>
<p>So although a <code>&lt;button&gt;</code> makes an appearance, it’s not part of a distinct group of buttons; its action applies directly to the navigation.</p>
<h2 id="keyboard-behaviour">Keyboard behaviour</h2>
<p>Unlike button groups, the keyboard behaviour for navigation is super simple and requires zero JavaScript if there isn’t a sub-nav:</p>
<ul>
<li><kbd>⇥</kbd> (Tab) moves focus from one link to the next</li>
<li><kbd>⇧</kbd> (Shift) + <kbd>⇥</kbd> moves focus backwards</li>
<li><kbd>⏎</kbd> (Return) follows a link</li>
</ul>
<p>That’s it!</p>
<p><i>Don’t forget to <a href="/blog/skip-links-what-why-and-how">use a skip link</a> so that users can jump past your navigation to interact with the main page content.</i></p>
<h3 id="adding-buttons-into-the-mix">Adding buttons into the mix</h3>
<p>If there’s sub-navigation (and therefore one or more buttons), things get slightly more complex:</p>
<ul>
<li><kbd>⇥</kbd> moves focus from one link or button to the next</li>
<li><kbd>⇧</kbd> + <kbd>⇥</kbd> moves focus backwards</li>
<li><kbd>⏎</kbd> (Return) follows a link</li>
<li><kbd>⏎</kbd> or <kbd>Space</kbd> presses a button</li>
<li><kbd>Esc</kbd> closes an open sub-nav</li>
</ul>
<p>When a button is pressed, focus should remain <em>on the button</em> so that it can be immediately closed if needed, and if the user wants to move focus into the sub-nav they’d press <kbd>⇥</kbd> (and keep pressing <kbd>⇥</kbd> to continue through the sub-nav).</p>
<p>In other words, unlike a menu in a menubar, the sub-nav should not show automatically when the trigger is focused, and focus should not move into the sub-nav automatically. The arrow keys should do nothing (other than scroll the page, as they usually do).</p>
<h3 id="when-does-a-sub-nav-close">When does a sub-nav close?</h3>
<p>The only question mark is when/if the sub-nav should close automatically. There are a couple of options when focus leaves the sub-nav or its trigger button:</p>
<ol>
<li>The sub-nav remains open</li>
<li>The sub-nav closes</li>
</ol>
<p>Option one needs two things to avoid overlapping sub-navs and covering page content outside the navigation by a still-open sub-nav:</p>
<ul>
<li>Close an open sub-nav when another sub-nav is opened</li>
<li>Close an open sub-nav when focus leaves the navigation</li>
</ul>
<p>I like things to be as simple as possible, so option 1 appeals to me. just close an open sub-nav when focus moves past it.</p>
<h2 id="nothing-more-to-add">Nothing more to add</h2>
<p>There’s really not a lot to it! Tab, tab, tab, and hit Return when you get to the page you want to visit. Nothing fancy and very easy to code, which is just as well as you’re going to need navigation on pretty much every project you work on!</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/how-navigation-should-work-for-keyboard-users">How navigation should work for keyboard users</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>How button groups should work for keyboard users</title>
    <link href="https://www.tempertemper.net/blog/how-button-groups-should-work-for-keyboard-users" />
    <id>https://www.tempertemper.net/blog/how-button-groups-should-work-for-keyboard-users</id>

    
    <published>2025-03-12T00:00:00Z</published>
    <updated>2025-03-12T00:00:25Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Menubars, menus, toolbars, and tablists are part of a larger family of ‘button groups’. Here’s how they should behave when using the keyboard.</summary>
        <category term="Accessibility" />
        <category term="Development" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>I’ve written about <a href="/blog/theres-no-such-thing-as-menubar-navigation">the difference between navigation and menubars</a>, where I mention that menubars should be few and far between on the web. But menubars are part of a larger family of ‘button groups’, which are fairly common.</p>
<p>Some members of the button group family are:</p>
<ul>
<li>Menubar</li>
<li>Menu</li>
<li>Toolbar</li>
<li>Tablist</li>
</ul>
<p>So how should button groups behave when using the keyboard?</p>
<h2 id="some-quick-oversimplified-examples">Some quick, oversimplified examples</h2>
<p>Before I dig into the commonalities of button group behaviour, it helps to understand what each type of button group is and how it might be marked up.</p>
<h3 id="menubars">Menubars</h3>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/menubar_role">MDN Docs describes menubars</a> as:</p>
<blockquote>
<p>a presentation of menu that usually remains visible and is usually presented horizontally</p>
</blockquote>
<p>Each item usually contains its own menu; think those File/Edit/View/etc. menubars at the top of Google Docs documents. A menubar’s markup might look something like:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>menubar<span class="token punctuation">"</span></span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Document menubar<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>menuitem<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>File<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!-- File menu goes here --></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>menuitem<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Edit<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!-- Edit menu goes here --></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>menuitem<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>View<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!-- View menu goes here --></span>
    <span class="token comment">&lt;!-- More menubar items --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre>
<p><i>This is an illustration and far from production code!</i> You’re going to want a bunch of other things on the menu items, like:</p>
<ul>
<li><code>aria-haspopup</code> to let screen reader users know if a item has a menu of its own (it probably does)</li>
<li><code>aria-controls</code> to make create a relationship between the menubar button and its menu</li>
</ul>
<h3 id="toolbars">Toolbars</h3>
<p>Toolbars are similar to menubars but are usually more focused on a particular purpose, like formatting text. <a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/toolbar_role">MDN Docs describes toolbars</a> as:</p>
<blockquote>
<p>a collection of commonly used function buttons or controls represented in a compact visual form.</p>
</blockquote>
<p>Here’s how the markup might look:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>toolbar<span class="token punctuation">"</span></span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Text formatting<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span><span class="token punctuation">></span></span>Bold<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span><span class="token punctuation">></span></span>Italic<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span><span class="token punctuation">></span></span>Bulletted list<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span><span class="token punctuation">></span></span>Numbered list<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
<span class="token comment">&lt;!-- Markup for the text editing area --></span></code></pre>
<p>Again, this is a huge oversimplification; among other things, you’re going to want:</p>
<ul>
<li><code>aria-controls</code> on the toolbar to hook it up to its text editing area</li>
<li>icons (SVGs, or some other kind of image) in place of the button text (one of the <a href="/blog/what-i-wish-was-in-wcag-prohibit-icon-only-buttons">few instances where icon-only buttons are probably okay to use</a>)</li>
<li><code>aria-pressed</code> to communicate whether a format has been applied or not</li>
<li><code>type=&quot;button&quot;</code> on all those <code>&lt;button&gt;</code> elements, to stop them submitting the form when pressed</li>
</ul>
<h3 id="menus">Menus</h3>
<p>Menus are found in all sorts of places: sometimes inside menubars and toolbars, sometimes as submenus inside other menus; sometimes on their own, like a right-click context menu or attached to Actions buttons on each item in a list. <a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/menu_role">MDN Docs describes menus</a> as:</p>
<blockquote>
<p>a type of composite widget that offers a list of choices to the user.</p>
</blockquote>
<p>Here’s how you might mark up a menu:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>actions<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Actions<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>menu<span class="token punctuation">"</span></span> <span class="token attr-name">aria-labelledby</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>actions<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>menuitem<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Move up<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>menuitem<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Move down<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>menuitem<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Edit<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>menuitem<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Delete<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre>
<p>Menus are pretty straightforward, so all I’d add is that you’ll want <code>aria-expanded</code> on the trigger button, if there is one. Oh, and if you’ve got submenus you’re going to want <code>aria-level</code> to inform screen reader users about how deep in the menu hierarchy they are, as well as some <code>aria-haspopup</code>, <code>aria-controls</code>, of course.</p>
<h3 id="tablist">Tablist</h3>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tablist_role">MDN Docs describes a tablist</a> like this:</p>
<blockquote>
<p>The tablist role identifies the element that serves as the container for a set of tabs.</p>
</blockquote>
<p>Pretty straightforward: a group of tabs. Here’s some example markup:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>tablist<span class="token punctuation">"</span></span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Tabs<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>tab<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Tab 1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>tab<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Tab 2<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>tab<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Tab 3<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!-- The rest of the tabs --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
<span class="token comment">&lt;!-- Contents of the tab that's currently active --></span></code></pre>
<p>Again, that’s oversimplified, so in your working code you’ll be reaching for:</p>
<ul>
<li><code>aria-controls</code> on each tab to match the <code>id</code> of its tab panel</li>
<li><code>aria-selected</code> to tell screen reader users whether or not the content for the tab they’re on is currently in view</li>
<li>the <code>hidden</code> attribute on the currently unselected tab panels</li>
</ul>
<h2 id="keyboard-behaviour">Keyboard behaviour</h2>
<p>Now you know what a button group is, it’s important they all work in the same way using the keyboard; especially as some can be contained within others, like menus inside menubars and toolbars. Buckle up as this gets complicated!</p>
<h3 id="a-single-tab-stop-for-keyboard-users">A single tab stop for keyboard users</h3>
<p>Once a keyboard user has tabbed onto the button group, they would then move from button to button using the arrow keys, rather than further tab presses. Another press of the <kbd>⇥</kbd> (tab) key should take focus off the button group and onto the next interactive element in the document.</p>
<p>So on top of the extra markup I mention after each example, you’re also going to want <code>tabindex</code> attributes on each button. JavaScript should listen for arrow key presses and clicks to shift both the <code>0</code>-value tabindex and the focus (via the <code>focus()</code> method) around, while ensuring the non-focused buttons have <code>tabindex=&quot;-1&quot;</code>.</p>
<p>Worth mentioning too that when tabbing onto a button group when no button has been selected, the first item should get focus. If a button has been selected, for example a tab in a tablist, focus goes directly to it.</p>
<h3 id="arrow-keys-to-get-around">Arrow keys to get around</h3>
<p>Speaking of key presses, once a button group has focus the arrow keys are the way to get around.</p>
<p>In horizontally laid-out groups the <kbd>→</kbd> (right) and <kbd>←</kbd> (left) keys move between the buttons; in vertically laid-out button groups it’s <kbd>↓</kbd> (down) and <kbd>↑</kbd> (up).</p>
<p>Of course these can be used in combination, for example a menubar where <kbd>→</kbd> and <kbd>←</kbd> move between items, and <kbd>↓</kbd> and <kbd>↑</kbd> move focus up and down one of its menus.</p>
<p>If each menu in a menubar or toolbar doesn’t open automatically on focus, pressing <kbd>↓</kbd> should open the menu and move focus to its first item. <kbd>⏎</kbd> (Return) or <kbd>Space</kbd> should do the same. <kbd>↑</kbd> usually places focus on the <em>last</em> item in the menu.</p>
<p>Whether <kbd>↓</kbd> when on the last menu item circles focus back up to the first or just stays put is up to you. I’d probably go with the last item being a dead-end to avoid risk of any disorientation. Ditto for horizontally laid-out button groups: <kbd>→</kbd> when on the last item (or <kbd>←</kbd> when on the first) could move focus to the first (or the last), but I wouldn’t do that.</p>
<p>When a menu item has a submenu, it should be opened with <kbd>→</kbd> (or <kbd>⏎</kbd> or <kbd>Space</kbd>) and focus should go to the submenu’s first item. <kbd>←</kbd> when in a submenu should close it and put focus back on it’s parent button.</p>
<h3 id="bells-and-whistles">Bells and whistles</h3>
<p>You could even add extra keyboard shortcuts, for example <kbd>Home</kbd> and <kbd>End</kbd> could move focus to the first and last items in a menu. <kbd>⌥</kbd> (Option) + <kbd>↑</kbd>/<kbd>↓</kbd> also does that on macOS.</p>
<p>Here’s another one that you’d find on macOS: <kbd>⌘</kbd> (Command) + <kbd>↓</kbd>/<kbd>↑</kbd> jumps from one section within a menu to the next.</p>
<p>In a menubar menu, and on a menu item without submenu, <kbd>→</kbd> could move focus to the next menu in the menubar. And <kbd>←</kbd> would do the same in the opposite direction.</p>
<h3 id="escape">Escape</h3>
<p>Menubars, toolbars, and tablists are always on view, but menus are normally hidden until triggered; the <kbd>Esc</kbd> key should close an open menu and put focus:</p>
<ul>
<li>back on the menu’s parent button if triggered by a button on-page, or as part of a toolbar</li>
<li>where the cursor is in the document’s editing area, if part of a menubar</li>
</ul>
<h2 id="screen-reader-users">Screen reader users</h2>
<p>Screen reader users will first hear the role of the button group, which will tell them that the button group style interaction pattern is required, rather than their normal screen reader navigation keys.</p>
<h3 id="orientation">Orientation</h3>
<p>So that screen reader users know which arrow keys to press (<kbd>→</kbd>/<kbd>←</kbd> or <kbd>↓</kbd>/<kbd>↑</kbd>) You could use <code>aria-orientation</code> to explicitly set the horizontal/vertical orientation of the button group, but this is:</p>
<ul>
<li>Not all that well supported across screen readers</li>
<li>Probably implicit in the button group type anyway (menubars, toolbars, and tabs are usually horizontal, menus normally vertical)</li>
</ul>
<h2 id="complex">Complex</h2>
<p>As you can see, button groups are fiddly components, requiring an awful lot of JavaScript to drive the various keypresses. But there’s some good news:</p>
<ul>
<li>Menubars are almost never what you need</li>
<li>Toolbars aren’t all that uncommon</li>
<li>Menus are fairly low complexity, especially when kept to one level</li>
<li>Tablists can (and often should) be avoided by using alternate designs, but at least they’re the simplest form of button group if you need to use one</li>
</ul>
<p>So for when you do need to use a button group, now you know how they should behave using the keyboard.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/how-button-groups-should-work-for-keyboard-users">How button groups should work for keyboard users</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>There’s no such thing as ‘menubar navigation’</title>
    <link href="https://www.tempertemper.net/blog/theres-no-such-thing-as-menubar-navigation" />
    <id>https://www.tempertemper.net/blog/theres-no-such-thing-as-menubar-navigation</id>

    
    <published>2025-02-28T00:00:00Z</published>
    <updated>2025-02-28T00:00:26Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>A problem markup and interaction pattern I encounter a lot is a result of people (understandably) following a misleading example from the W3C.</summary>
        <category term="Accessibility" />
        <category term="Development" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>There’s a problem markup and interaction pattern I encounter again and again. Developers search the web with the intention of creating the most accessible navigation, and often end up on <a href="https://www.w3.org/WAI/ARIA/apg/patterns/menubar/examples/menubar-navigation/">this example of navigation from the W3C</a>. But <strong>this is not how navigation should work</strong>.</p>
<p>I’m not sure there’s such a thing as ‘menubar navigation’:</p>
<ul>
<li>Menubars are for actions</li>
<li>Navigation is for, well, navigating</li>
</ul>
<p>Before we dig into the differences between those, let’s talk about a big red flag I spotted with the W3C’s menubar navigation oxymoron.</p>
<h2 id="html-should-be-simple">HTML should be simple</h2>
<p>The whole point of HTML is that it’s easy to write. Almost every website needs a navigation so it should use the simplest of markup. Looking at the <a href="https://codepen.io/pen?&amp;prefill_data_id=785985a3-ea1e-456b-a0d6-b3b9b331ac59">code for the W3C’s example</a>, there are over 70 lines of JavaScript. That’s a lot for something that should be straightforward to implement.</p>
<p>Overly-complex code is usually an indicator that something isn’t right.</p>
<h2 id="menubars-are-not-navigation">Menubars are not navigation</h2>
<p>Okay, so what exactly is the difference between menubars and navigation? I mentioned above that it’s about actions versus navigating, but what does that mean?</p>
<h3 id="menubars">Menubars</h3>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/menubar_role">MDN Docs describes menubars</a> in this way:</p>
<blockquote>
<p>A menu is a widget that offers a list of choices to the user, such as a set of actions or functions. The menubar type of menu is usually presented as a persistently visible horizontal bar of commands.</p>
</blockquote>
<p>So a menubar is a top-level, always-visible menu. And it’s for “actions or functions”.</p>
<p>The menubar for an app on macOS is a good example: it has a bunch of common top-level groupings like File, Edit, and View; inside each is a menu, containing actions like ‘Export’, ‘Print’, ‘Copy’, ‘Paste’, ‘Enter Full Screen’, show/hide sidebars, toolbars, etc. Those are about interacting with your document or changing your editing experience.</p>
<p>Actions/functions are triggered by buttons (via the <code>&lt;button&gt;</code> element), <em>so menubars and menus are for buttons</em>.</p>
<h3 id="navigation">Navigation</h3>
<p>Navigation, on the other hand, is about going places via <em>links</em> (the <code>&lt;a&gt;</code> element); you press a link and are taken somewhere else. Of course, buttons feature too, but they’re usually to show/hide sub-navigation, so are actions that make sense in the context of navigation. The crucial thing is that the last action you take when navigating is always going to a new place.</p>
<p>Links to other places use the <code>&lt;a&gt;</code> element (<a href="/blog/links-missing-href-attributes-and-over-engineered-code">don’t forget the <code>href</code> attribute</a>). <em>Navigation is for links</em>.</p>
<h2 id="youre-probably-never-going-to-need-a-menubar">You’re probably never going to need a menubar</h2>
<p>While navigation is super common on the web, menubars are, or at least should be, few and far between. Again, from MDN Docs:</p>
<blockquote>
<p>Menubars behave like native operating system menubars, such as the menubars containing pull down menus, commonly found at the top of many desktop application windows.</p>
</blockquote>
<p>We’re talking about websites, so “operating system menubars” aren’t really needed very much. In fact, the only application I can think of for a menubar is a browser-based app that mimics a native application, such as Google Docs where that File/Edit/View/Insert/etc. menubar is definitely relevant.</p>
<h2 id="confusing-for-keyboard-users">Confusing for keyboard users</h2>
<p>The keyboard behaviour for a menubar is very different to the keyboard behaviour for a navigation. A keyboard user’s expectations for a navigation are simple: they’re links, so the <kbd>⇥</kbd> (tab) key should take them from one to the next; when they reach the link to the place they want to go to, they follow it with <kbd>⏎</kbd> (Return).</p>
<p>Negotiating a menubar, once an item in the menubar has focus, is generally about the arrow keys to move around and <kbd>⏎</kbd> or <kbd>Space</kbd> to press a button.</p>
<p>If a keyboard user sees navigation, they will expect to be using the tab key a fair amount, but not with the W3C’s pattern, as it behaves like a menubar. Instead of moving to the second item in the navigation, their second tab press will move their focus <em>off</em> the navigation, meaning they’ll have to <kbd>⇧</kbd> (Shift) tab back onto it and try menubar-style keypresses in the hope they work.</p>
<h2 id="confusing-for-screen-reader-users">Confusing for screen reader users</h2>
<p>The W3C example wraps the menubar in a navigation landmark (via the <code>&lt;nav&gt;</code> element) so there is some indication for screen reader users that it’s navigation, but it’s confusing: first there’s the information that it’s navigation, then that it’s a menubar. Is the navigation role a mistake? Is the menubar role a mistake? Or maybe it’s one of those annoying websites that follows the W3C ‘Navigation Menubar’ markup pattern…</p>
<h2 id="i-get-it">I get it</h2>
<p>The W3C produce the <a href="https://www.w3.org/TR/WCAG/">Web Content Accessibility Guidelines (WCAG)</a> so if they’re suggesting navigation should be marked up like a menu, why would people question that?</p>
<p>There is a warning saying “A pattern more suited for typical site navigation with expandable groups of links is the Disclosure Pattern”, but how many readers will notice this, especially as ‘Navigation’ is the first word in the main heading of the page they’re already on?</p>
<p>On top of this, there are apparent benefits the W3C’s pattern; particularly for keyboard users, who would only have a single tab stop on the W3C’s example. That seems like a good way to get from the top of the page to the main content of the page quickly, but there’s a better way to do that: <a href="/blog/skip-links-what-why-and-how">a skip link</a>.</p>
<p>The pattern itself is fine for menubars, so the best thing for the W3C to do would be to change the example and remove any reference to the pattern being in any way ‘navigation’.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/theres-no-such-thing-as-menubar-navigation">There’s no such thing as ‘menubar navigation’</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Skip links: what, why, and how</title>
    <link href="https://www.tempertemper.net/blog/skip-links-what-why-and-how" />
    <id>https://www.tempertemper.net/blog/skip-links-what-why-and-how</id>

    
    <published>2025-02-23T00:00:00Z</published>
    <updated>2025-02-23T00:00:27Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Ever noticed one of those “Skip to main content” links when you press the tab key? They’re important.</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>If you’re like me an you’re a bit of a hybrid mouse/keyboard user, you might have noticed something as you browse the web: pressing the <kbd>⇥</kbd> (tab) key when you land on a website sometimes causes a previously-hidden “Skip to main content” (or words to that effect) link to appear.</p>
<p>‘Skip links’ are a great way for keyboard-only users to move their focus past the header and navigation of a web page, directly to the main content area so they can begin interacting with the page.</p>
<p>This is so important that the Web Content Accessibility Guidelines (WCAG) contains a rule called <a href="https://www.w3.org/TR/WCAG/#bypass-blocks">2.4.1 Bypass Blocks</a>, which says:</p>
<blockquote>
<p>A mechanism is available to bypass blocks of content that are repeated on multiple web pages.</p>
</blockquote>
<h2 id="why-is-this-so-important">Why is this so important?</h2>
<p>Imagine there’s an interesting looking link in the opening paragraph of a blog post:</p>
<ul>
<li>A mouse/trackpad user only has to move their cursor from wherever it’s currently resting to the link</li>
<li>A touch-screen user would just tap the link</li>
<li>A speech recognition software user would say the command to ‘click’ the link</li>
<li><a href="/blog/not-all-screen-reader-users-are-blind">A sighted or partially sighted screen reader user</a> could move their cursor to the main heading of the page with a quick keyboard shortcut, then jump to the link</li>
<li>A blind screen reader user wouldn’t not know the link was there on page load, but they will quickly discover it after jumping to the main heading and reading through the first paragraph of content</li>
</ul>
<p>But it’s not so easy for a keyboard-only user; especially when there are a lot of navigation items, even multiple blocks of navigation, to tab past.</p>
<ul>
<li><a href="https://www.amazon.co.uk">Amazon’s homepage</a> currently has 44 tab stops before the main page content</li>
<li>MDN Docs has 38 in the main header, plus any breadcrumb navigation, a language switcher, links to related articles (sometimes over 100), and an outline of the article</li>
<li><a href="https://en.wikipedia.org/wiki/Main_Page">Wikipedia</a> has 18 tab stops before the article-specific navigation</li>
<li>GitHub has 11</li>
<li>Even the relatively navigation-light GOV.UK can have up to 6 or so, depending on the page</li>
</ul>
<p>Keyboard-only users are often keyboard-only users because they have a motor impairment that prevents them using a mouse; this often means they experience fatigue quickly. Repeatedly pressing the tab key before getting to the main chunk of content can be a lot of work, particularly when this would have to be done on <em>every page</em>. Luckily, all of the examples I list above have a skip link of some sort, meaning it’s a single <kbd>⇥</kbd> press to show and focus the skip link, then <kbd>⏎</kbd> (Return) to follow it.</p>
<h2 id="how-to-do-it">How to do it</h2>
<p>Skip links are great. And they’re really easy to implement too, requiring zero JavaScript. First, the HTML:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>header</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#main<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>skip-link<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
        Skip to main content
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!-- Header and navigation content --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>header</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>main</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>main<span class="token punctuation">"</span></span> <span class="token attr-name">tabindex</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!-- Page contents --></span></code></pre>
<p>No fancy code there:</p>
<ul>
<li>A main content container with an <code>id</code></li>
<li>A link that goes to that <code>id</code></li>
<li>The link has a class, so that we can add CSS to show/hide it</li>
<li>The <code>&lt;main&gt;</code> element has a <code>tabindex=&quot;-1&quot;</code> to to ensure browsers put focus on it reliably</li>
</ul>
<p>And the CSS?</p>
<pre class="language-css" tabindex="0"><code class="language-css"><span class="token selector">.skip-link:not(:focus):not(:active)</span> <span class="token punctuation">{</span>
  <span class="token property">clip-path</span><span class="token punctuation">:</span> <span class="token function">inset</span><span class="token punctuation">(</span>50%<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">height</span><span class="token punctuation">:</span> 1px<span class="token punctuation">;</span>
  <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span>
  <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span>
  <span class="token property">white-space</span><span class="token punctuation">:</span> nowrap<span class="token punctuation">;</span>
  <span class="token property">width</span><span class="token punctuation">:</span> 1px<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">main:focus</span> <span class="token punctuation">{</span>
  <span class="token property">outline</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>This looks a bit more complex (<a href="https://www.tpgi.com/the-anatomy-of-visually-hidden/">TPGi have a good breakdown of the technique</a>), but all it’s doing is:</p>
<ul>
<li>Visually hiding the skip link when it doesn’t have focus</li>
<li>Showing the skip link when it receives focus</li>
<li>Preventing the main content container getting a focus outline when the skip link is followed (since a focus indicator would suggest it’s interactive, and it’s not; plus focus can’t be placed back onto it manually so an indicator would be doubly misleading)</li>
</ul>
<p>That’s it!</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/skip-links-what-why-and-how">Skip links: what, why, and how</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Ensure your project works in every browser and for every user</title>
    <link href="https://www.tempertemper.net/blog/ensure-your-project-works-in-every-browser-and-for-every-user" />
    <id>https://www.tempertemper.net/blog/ensure-your-project-works-in-every-browser-and-for-every-user</id>

    
    <published>2025-01-30T00:00:00Z</published>
    <updated>2025-01-30T00:00:28Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Going through my backlog of blog ideas, I spotted a quote that I thought was worth sharing.</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>I have a backlog of draft articles in <a href="https://www.tempertemper.net/blog/in-search-of-the-best-writing-app">my favourite writing app</a>. If I have an idea for a blog post I open a new document and scribble my thoughts down; I’ll then pick it back up again when I’m in writing mode. Going through my backlog of ideas, I spotted a link and a quote from a <a href="https://webkit.org/blog/14955/the-web-just-gets-better-with-interop/">WebKit blog about the Interop project</a> I’d read last February.</p>
<blockquote>
<p>It’s your job as a web developer to ensure your project works in every browser and for every user — and that can be hard to do.</p>
</blockquote>
<p>Yep, yep, and yep.</p>
<p>It’s been part of every web-based project’s workflow for a couple of decades to test across multiple browsers and operating systems. I still shudder when I remember wrestling with Internet Explorer 6 quirks; nowadays (thanks to projects like Interop itself and the https://www.webstandards.org before it) it’s much less time consuming to find and fix cross-browser bugs.</p>
<p>As for the <q>and for every user</q> part, that’s what <em>really</em> caught my attention. It’s my job as an accessibility specialist to make sure that the many products in my remit work, or are on their way to working, for all users.</p>
<p>“All users” includes disabled people, so I do a lot of educating and training to ensure designers, developers, testers, user researchers, project owners, etc., etc., are delivering work that’s as accessible as possible. As Jen Simmons says in the Interop article, it’s hard work.</p>
<p>It’s hard work because it means a <a href="https://www.tempertemper.net/blog/if-youre-going-to-do-a-job-do-it-properly">change in mindset for product delivery teams</a>, it’s hard work because <a href="https://www.tempertemper.net/blog/user-wants-versus-accessibility">it means change for existing users of products</a>. But it’s worth it.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/ensure-your-project-works-in-every-browser-and-for-every-user">Ensure your project works in every browser and for every user</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Using iframes to embed arbitrary content is probably a bad idea</title>
    <link href="https://www.tempertemper.net/blog/using-iframes-to-embed-arbitrary-content-is-probably-a-bad-idea" />
    <id>https://www.tempertemper.net/blog/using-iframes-to-embed-arbitrary-content-is-probably-a-bad-idea</id>

    
    <published>2024-12-29T00:00:00Z</published>
    <updated>2024-12-29T00:00:29Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>The iframe element is a way to embed one website inside of another. Useful for things like maps or videos, but not so much for other content.</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>The <code>&lt;iframe&gt;</code> element is a way to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe">embed one web page inside of another</a>. They’re often used to deliver a video, <a href="https://design-system.service.gov.uk/components/text-input/">working code example</a>, or video as part of other page content, which is pretty sensible, but I’ve seen them being suggested as a way to embed general text-based page content, which is problematic.</p>
<h2 id="general-fixed-height-weirdness">General fixed-height weirdness</h2>
<p>First up, unless the contents of our iframe makes sense as a fixed canvas (or a canvas with fixed proportions), things are going to get a bit weird for the user. We’ve no idea how much room the content in the iframe will need and therefore no idea how big the iframe should be.</p>
<p>Setting <code>height</code> and <code>width</code> attributes on our iframe when embedding a map makes sense as we’ve configured how the map should be displayed and know how it will appear on our site. For arbitrary page content, however, we don’t know how much space will be taken up.</p>
<p>Since we need to set a height on our container (which will also avoid <a href="https://web.dev/articles/cls">Cumulative Layout Shift</a>), we’re unlikely to get the dimensions exactly right:</p>
<ul>
<li>If the iframe is too big for the content there will be empty space between the end of the content and the end of the iframe</li>
<li>If, more likely, the iframe is smaller than the content presented inside of it, it will have to scroll independently of the parent page</li>
</ul>
<h2 id="keyboard-users">Keyboard users</h2>
<h3 id="tabbing-inconsistencies">Tabbing inconsistencies</h3>
<p>The keyboard behaviour of iframes is slightly inconsistent from browser to browser. Most browsers don’t include iframes in the page’s tab index, which makes a pretty seamless experience for keyboard users who would tab from the last interactive element on the parent page before the iframe, to the first interactive element in the iframe.</p>
<p>But Apple’s Safari, when <a href="/blog/how-to-use-the-keyboard-to-navigate-on-safari">full keyboard access is turned on</a>, includes the iframe in the tab index <em>the first time</em> it is encountered. Subsequent attempts to tab onto the iframe won’t work and it will behave just like Firefox, Chrome, and Chromium-based browsers.</p>
<p>That’s something we’ll have to live with as removing the tab stop with <code>tabindex=&quot;-1&quot;</code> causes the browser ignore the iframe and everything inside it, which you really wouldn’t want to do as it would make the iframe completely inaccessible for keyboard-only users.</p>
<p>Evening things up by adding <code>tabindex=&quot;0&quot;</code> to the iframe wouldn’t be a great idea as it would add an unexpected tab stop for keyboard users who wouldn’t normally expect one. But the good (?) news is that adding <code>tabindex=&quot;0&quot;</code> to an <code>&lt;iframe&gt;</code> element does nothing at all to the default behaviour, regardless of browser.</p>
<h3 id="scrolling">Scrolling</h3>
<p>Aside from it being an odd experience, scrolling the content inside an iframe could present a real accessibility issue for keyboard-only users if there are no interactive elements in the embedded content. If the user can’t tab onto an interactive element in the iframe they can’t enter the embedded document, and if they can enter the document they can’t scroll it.</p>
<p>So there’s some logic to Safari’s decision to add iframes to the page’s tab index as it means embedded content can always be scrolled, at least the first time it receives focus.</p>
<h2 id="screen-reader-users">Screen reader users</h2>
<p>iframes need to have an accessible name (which is done via the <code>title=&quot;&quot;</code> attribute) in order to satisfy <a href="https://www.w3.org/TR/WCAG/#name-role-value">4.1.2 Name, Role, Value</a> in the Web Content Accessibility Guidelines (WCAG), since an iframe counts as a ‘user interface component’.</p>
<p>That way, the accessible name of each iframe would be announced to screen reader users before they reached the content in the embedded document. For something like a code example, that makes perfect sense, but for general page content it would:</p>
<ul>
<li>potentially confuse screen reader users who wouldn’t expect general page content to be brought in via iframes</li>
<li>create extra noise for screen reader users</li>
<li>cause extra work for authors, who would have to design a sensible descriptive name for the iframe</li>
</ul>
<p>What’s more, iframes aren’t navigated like normal content by all screen reader software. To use Apple’s VoiceOver for macOS as an example, when you reach an iframe you can’t just press on through the content with the VoiceOver key (usually <kbd>⌃</kbd> (Control) + <kbd>⌥</kbd> (Option)) and <kbd>→</kbd> (right); instead you’re stopped at the iframe itself and have to move ‘into’ it using the VoiceOver key, <kbd>⇧</kbd> (Shift) + <kbd>↓</kbd> (down). Clunky.</p>
<h2 id="control">Control</h2>
<p>Aside from all of the usability issues with iframes, the biggest issue for me is one of control. The embedded page within your control? It might belong to another department within your organisation or a different organisation entirely.</p>
<h3 id="responsiveness">Responsiveness</h3>
<p>If that organisation is YouTube and the content you’re embedding is a video from their platform, you can be reasonably confident that they’ll do their best to ensure the content they serve will always match the <code>height</code> and <code>width</code> attributes they set on the embed code snippet they provided. It’s in their interests to ensure their content is nicely presented out there on the web, so the video will scale up and down nicely as the iframe changes width across various screen sizes.</p>
<p>But if the content you have embedded changes without the kind of rigorous testing that YouTube are sure to carry out, or a bug is introduced that affects its responsiveness, you risk falling short WCAG’s <a href="https://www.w3.org/TR/WCAG/#reflow">1.4.10 Reflow</a> and <a href="https://www.w3.org/TR/WCAG/#resize-text">1.4.4 Resize Text</a> as the content in the iframe becomes inaccessible for some people.</p>
<h3 id="bug-fixes-and-maintenance">Bug fixes and maintenance</h3>
<p>Even if you’ve got control of the embedded document, that’s two websites to maintain, rather than just one. And if you don’t have full control of the embedded document, you’re at the mercy of the people who are: their project priorities may not be the same as yours, and accessibility might be further down on their list, so you could be waiting a long time for any bugs you raise to be ironed out.</p>
<h3 id="testing">Testing</h3>
<p>Quality assurance testing can get trickier too, as <a href="https://codepen.io/stevef/full/YLMqbo">handy bookmarklets</a> don’t affect content inside of iframes, and more complex browser-based tools like <a href="https://dequeuniversity.com/rules/axe/4.2/frame-tested">axe DevTools don’t support testing of documents in iframes</a>.</p>
<h2 id="to-sum-up">To sum up</h2>
<p>The working title for this post was “iframes? More like cryframes, amirite!?”. In case it isn’t already clear what my advice would be for using iframes to embed arbitrary web content inside other documents: don’t.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/using-iframes-to-embed-arbitrary-content-is-probably-a-bad-idea">Using iframes to embed arbitrary content is probably a bad idea</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Avatars and alt text</title>
    <link href="https://www.tempertemper.net/blog/avatars-and-alt-text" />
    <id>https://www.tempertemper.net/blog/avatars-and-alt-text</id>

    
    <published>2024-11-19T00:00:00Z</published>
    <updated>2024-11-19T00:00:30Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>I really enjoyed Nicolas Steenhout’s recent article on Alt text for avatars or user photos. But there is a context where I would break his rule…</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>I really enjoyed Nicolas Steenhout’s recent article on <a href="https://nicolas-steenhout.com/alt-text-for-avatars/">Alt text for avatars or user photos</a>. He highlights the importance of ensuring users are provided with the same information visually and non-visually via HTML, saying:</p>
<blockquote>
<p>User photos and avatars are informational images. Do use clear and concise alternate text to describe them. Otherwise blind screen reader users won’t have access to the same information as sighted people.</p>
</blockquote>
<p>Agreed! So why am I writing this? Well, there is a context in which user avatars should be:</p>
<ul>
<li>presented visually</li>
<li>hidden from assistive technology like screen reader software</li>
</ul>
<p>Where I work there are lots of lists; some present bank transactions, some payslips, and some present people. Many of those lists of people include their avatar photo, which is a great visual hooks for people glancing through the list. But is it useful to convey the same information to blind screen reader users?</p>
<p>As long as the avatars sit alongside the person’s name and a bunch of other information, all of which is enough to identify the person, I’d say the description of the person is superfluous.</p>
<p>A blind screen reader user should get the same <em>experience</em> as a sighted user: fly through that list to quickly identify each person until they land on the one they’re after. But if they get exactly the same <em>content</em> it could be a worse experience.</p>
<p>So, in this context, I’d use an empty ‘alt’ tag for each image, like this:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>martin-underhill.jpg<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>name<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Martin Underhill<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!-- Rest of the information --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span></code></pre>
<p>The alternative would be unnecessary information in our context:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>martin-underhill.jpg<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>A friendly looking man with a bald head, beard, and glasses.<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>name<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Martin Underhill<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!-- Rest of the information --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span></code></pre>
<p>Of course, as Nicolas says, describe the avatar photos in other places, like each person’s profile page. But, just as an icon that is paired with some text can provide a visual hook only and should be hidden from assistive technology, a user avatar or photo is sometimes only for sighted users.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/avatars-and-alt-text">Avatars and alt text</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Upgrading from iPhone 13 mini to 16 Pro</title>
    <link href="https://www.tempertemper.net/blog/upgrading-from-iphone-13-mini-to-16-pro" />
    <id>https://www.tempertemper.net/blog/upgrading-from-iphone-13-mini-to-16-pro</id>

    
    <published>2024-11-14T00:00:00Z</published>
    <updated>2024-11-14T00:00:31Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>I get a new phone every 3-ish years, give mine to my wife, and now she gives hers to our daughter. I got a 16 Pro this year! Here’s the skinny.</summary>
        <category term="Apple" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>I usually get a new phone every 3 years. This works quite well I set my wife up on my old phone and, now that my daughter is old enough to have one, she gets my wife’s.</p>
<p>Three years ago I <a href="/blog/upgrading-from-iphone-xs-to-13-mini">upgraded to an iPhone 13 Mini from an iPhone XS</a> and now it was time to pass my beloved 13 Mini down the chain. I’ve just bought myself a 16 Pro; here’s what I’ve noticed in the upgrade.</p>
<h2 id="camera">Camera</h2>
<p>My two-models-ago XS had a nifty 2x zoom lens, which I found myself using a good amount. It was great for getting a better shot of my kids playing and, for some reason (I’m very much not a photographer), I preferred the photos it took.</p>
<p>I loved my 13 Mini. Loved it. But I missed that zoom lens. I was taking photos of my kids playing together on the beach this summer and zoom would have made for some much better snaps.</p>
<p>I did considered the standard 16, with its 2x telephoto, but the 5x lens on the Pro models was too much to resist. And it looks great. All the cameras do!</p>
<h2 id="camera-control">Camera Control</h2>
<p>The Camera Control feels like a nice idea but I initially found it irritating. I would accidentally launch the camera app while doing other things, particularly when adjusting the volume down… My grip on the opposite side of the phone as I squeeze the volume buttons is low, in order to avoid the Side Button which would take a screen shot or lock the phone; low enough to press the Camera Control. This is also not helped by the fact that it’s flush to the side of the phone, rather than slightly raised like all the rets of the buttons.</p>
<p>I’ve circumvented this by requiring a double click to open the camera in Settings → Camera → Camera Control → Double Click.</p>
<p>The problem now is one of software as I have to triple click to open the camera when the phone is locked: once to wake the phone and twice to launch the camera. If the phone is awake, I should be double clicking, but I still end up triple clicking which means I launch the camera and immediately take a photo. Looks like this is being addressed in iOS 18.2 where they’ve added and option to <a href="https://9to5mac.com/2024/11/11/ios-18-2-beta-3-camera-control-toggle/">bypass the ‘waking’ bit</a> and launch the camera with a single or double press, depending on your settings, whether it’s awake or not.</p>
<p>Finally, I find the camera control itself really fiddly. The half-press, the double half-press, and the swipe/scroll gestures are just too fiddly. I’d like some way to configure the control in Settings rather than when taking a photo. Or at least limit what accidental swipes can do. It just doesn’t feel well tested.</p>
<h2 id="action-button">Action Button</h2>
<p>Since getting my first Apple Watch, I’ve always use my phone on silent, preferring a tap on the wrist for notifications, so I haven’t used the Mute Switch in <em>years</em>. The Action Button is a great idea for people like me.</p>
<p>I’ve assigned the Torch to the Action Button, as I use the torch all the time, and it’s now super convenient to access with a long press of the Action Button. I’ve also removed the torch from both Control Centre and my Lock Screen, freeing up space for other utilities.</p>
<p>One small gripe, though, is that the Action Button isn’t quitez  far enough away from the volume buttons, so I often press it when I’m fumbling to turn the volume up.</p>
<h2 id="dynamic-island">Dynamic Island</h2>
<p>I like the Dynamic Island a <em>lot</em>. The design is delightful and it’s a super clever way to lean into the (for now) necessary cut-out to accommodate the front camera and sensors, but <a href="/blog/apple-youre-doing-the-dynamic-island-wrong">I don’t think Apple have got the interaction pattern quite right</a>.</p>
<h2 id="battery">Battery</h2>
<p>I was very conscious of my battery with the 13 Mini. It was fine, but it was always in the back of my mind. I had a MagSafe Battery Pack (<a href="https://daringfireball.net/linked/2023/09/16/magsafe-battery-pack-and-duo-charger">now unfortunately discontinued</a>) which got frequent use, but it has been passed to my wife alongside the 13 Mini as the 16 Pro lasts all day and more.</p>
<h2 id="screen">Screen</h2>
<p>The Always-On feature is taking some getting used to. It’s weird that the screen doesn’t turn off, and I had imagined the wallpaper would be dimmed further than it is when in Always-On. I guess it makes me uneasy because I was was so conscious of the battery in my little 13 Mini, but Apple must know what they’re doing so I’m leaving the feature switched on.</p>
<p>I now have Pro Motion, which is one of those stealth features that makes a huge difference but is something you’ll never notice. The 120 frames per second refresh rate make the phone feel ridiculously smooth and responsive, and it’s only when you go back that you realise how nice it is; like when I was setting up my wife’s on my outgoing 13 Mini.</p>
<p>The screen is also <em>really</em> big too, and the smaller bezels make a difference. Though I’m back to it feeling slightly insecure in hand, as there’s more stretching to reach much of the screen. I’m making good use of <a href="/blog/ios-14s-back-tap-a-better-way-to-access-control-centre">Back Tap</a> for Control Centre and Reachability, which has helped.</p>
<h2 id="case">Case</h2>
<p>Apple have stopped doing leather cases, which I understand, but I did love their leather cases. I got one of their silicon cases instead, which is nice but doesn’t slide in and out of my pocket as nicely as the leather case. One perk is that it feels more grippier in hand, offsetting the slightly insecure feeling while reaching around the screen on a much bigger device.</p>
<h2 id="usb-c">USB-C</h2>
<p>This has taken a wee bit of adjusting to. I’ve had to buy a new cable for the car (I need to plug the phone in to use CarPlay) and I decided to go the <a href="https://www.apple.com/uk/shop/product/MX6Y3ZM/A/magsafe-charger-2m?fnode=b15a3860dc6bc58db16a49038c58b0fdb736360caf6ebc0ff4a324dd090e404621f55ec6b5ace8b268c2bdbca311b069bf1a4a1ca53ee4394c9efb070fb40c1ec0b1e26852a0b513e634e67dfd6826aa31f24ec0d6bbfaab7aa9f408aaf318ef">MagSafe Charger</a> route for miscellaneous charging around the house, since that’s compatible with my wife’s phone too.</p>
<p>Overall, though, it’s probably better than Lightning: faster to charge and easy to pinch a charge when I’m working from my MacBook (I use USB-C to charge as, unlike the MagSafe charger, it can be plugged in on either side of the laptop). Problem is, I’m now finding myself wishing all of my peripherals (mouse, keyboard, etc.) were USB-C too!</p>
<h2 id="speakers">Speakers</h2>
<p>Not much to say here except the sound quality is really, really good.</p>
<h2 id="conclusion">Conclusion</h2>
<p>I like my 3-ish years upgrade cadence. If I upgraded each year I don’t think I would appreciate the new features quite as much. Plus it would be very expensive! This 16 Pro is an amazing piece of hardware; on balance I prefer the larger size and I’m looking forward to putting the camera through its paces!</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/upgrading-from-iphone-13-mini-to-16-pro">Upgrading from iPhone 13 mini to 16 Pro</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Apple, you’re doing the Dynamic Island wrong</title>
    <link href="https://www.tempertemper.net/blog/apple-youre-doing-the-dynamic-island-wrong" />
    <id>https://www.tempertemper.net/blog/apple-youre-doing-the-dynamic-island-wrong</id>

    
    <published>2024-11-08T00:00:00Z</published>
    <updated>2024-11-08T00:00:32Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>I love the idea of Dynamic Island; making lemons into lemonade and all that. But, in my opinion, Apple have got the fundamentals mixed up.</summary>
        <category term="Apple" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>I love the idea of Dynamic Island; making lemons into lemonade and all that. Apple have turned a hardware constraint into something practical and delightful.</p>
<p>I like that I don’t notice that there’s some inactive space where the cameras/sensors are. The animations they’ve used feel perfect, making it feel almost alive. I like that it offers a visual element to the iPhone’s background activity like playing music or a podcast. But it’s flawed.</p>
<p>There are two ways in interact with the app that’s running in the Dynamic Island:</p>
<ol>
<li>As a widget, up there at the top of the screen</li>
<li>In the app itself</li>
</ol>
<p>You access each of these via the Dynamic Island with either a tap or a long-press. Before you read any more, take a moment to think about which way round this should be.</p>
<p>Me? I would expect a quick tap would open the Dynamic Island so I could interact with it as a widget:</p>
<ul>
<li>Pause/play, scrubbing, skip back/forward a track in Music</li>
<li>Loud speaker, mute, phone down in Phone</li>
<li>Check who scored in Apple Sports’ Live Activity</li>
</ul>
<p>So a quick tap would offer a wee bit more functionality or information that you can access with a tap.</p>
<p>A long press should do something weightier, more deliberate, like taking me away from the app I’m currently using and land me on the relevant page of the app that was running in the Dynamic Island.</p>
<p>But it’s the other way round…</p>
<p>A tap on the Dynamic Island opens the app that’s running in there, taking you away from the app you’re currently using. I accidentally do this all the time, thinking I’ll trigger the widget popover…</p>
<p>A long press does that, of course. But how many people will think to long press? It makes the multi-tasking dimension the Dynamic Island brings both less discoverable and more awkward to access.</p>
<p>I’m assuming Apple’s thinking is that, since tapping an app icon on the Home Screen launches the app, the same should happen with the Dynamic Island. But it isn’t an app: it’s the Dynamic Island!</p>
<p>Again, I can see where they’re going with the long press. A long press usually triggers a popover, like a context menu, and the widget is like a popover, overlaying the app beneath it.</p>
<p>The logic of the design language may be right, but it <em>feels</em> wrong.</p>
<p>Let the user access the app’s widget first, <em>then</em> the app itself with a tap of the widget. Two quick taps. Or if you want to bypass the second tap, and therefore the widget, a long press of the Dynamic Island makes sense.</p>
<p>In theory, there’s good news in that this is a software thing, rather than baked into the hardware, and can therefore be changed relatively easily, but the Dynamic Island has been around for three iOS releases so I doubt Apple agree with me.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/apple-youre-doing-the-dynamic-island-wrong">Apple, you’re doing the Dynamic Island wrong</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Getting started with NVDA</title>
    <link href="https://www.tempertemper.net/blog/getting-started-with-nvda" />
    <id>https://www.tempertemper.net/blog/getting-started-with-nvda</id>

    
    <published>2024-10-02T00:00:00Z</published>
    <updated>2024-10-02T00:00:33Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Everyone who works in digital product development should be familiar with screen reader software. Here’s how to get started with NVDA on Windows.</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>In my opinion, everyone who works in digital product development should be at the very least familiar with screen reader software. Some, though, should have a working knowledge of how to use it.</p>
<p>I’ve written about how to <a href="/blog/getting-started-with-voiceover-on-macos">get started with VoiceOver on macOS</a> but VoiceOver is an Apple-only screen reader so what if you’re a Windows user?</p>
<p>The good news is you’ve got plenty of options, from the built-in Narrator to the two most widely used screen readers in the world: JAWS and NVDA. Let’s talk about the latter.</p>
<p>Page contents:</p>
<nav aria-label="Page contents">
<ol>
<li><a href="#install-nvda">Install NVDA</a></li>
<li><a href="#open-your-web-browser">Open your web browser</a></li>
<li><a href="#configure-nvda">Configure NVDA</a></li>
<li><a href="#navigation-commands-to-get-started">Navigation commands to get started</a></li>
<li><a href="#form-filling">Form filling</a></li>
</ol>
</nav>
<h2 id="install-nvda">Install NVDA</h2>
<p>NVDA isn’t built in to Windows, so the first thing you need to do is <a href="https://www.nvaccess.org/download/">download the most recent version for free</a>.</p>
<p>When setting up, make sure NVDA doesn’t launch on startup as you’re probably not going to want it running all the time. For when you do want to do some testing with it, it’s a good idea to pin the app to your Taskbar so that it’s easy to fire up whenever needed.</p>
<h2 id="open-your-web-browser">Open your web browser</h2>
<p>This bit is much easier than with VoiceOver on Mac since NVDA works with any browser you might have on Windows. <a href="https://www.gov.uk/service-manual/technology/testing-with-assistive-technologies#which-assistive-technologies-to-test-with">GOV.UK recommend</a> testing with Firefox, Chrome, or Edge, but every other browser I can think of is based on the same Chromium engine that Chrome and Edge are built on, so you can test with Opera, Brave, Vivaldi; whatever you like.</p>
<p>Having said that, GOV.UK list only Chrome or Edge as the browsers to test with JAWS, so I like to reserve Chromium browsers for JAWS and use Firefox for my NVDA testing; that way I get as broad a sweep of browsers in my testing as possible.</p>
<h2 id="configure-nvda">Configure NVDA</h2>
<p>Like with most software you test with, the default settings are pretty much what you want to be testing with since <a href="https://archive.uie.com/brainsparks/2011/09/14/do-users-change-their-settings/">very few users will change them</a>.</p>
<p>But there are a few things I do to make NVDA more useable for me, all of which you’ll find by going to NVDA in the Taskbar’s System Tray.</p>
<h3 id="prevent-automatic-reading">Prevent automatic reading</h3>
<p>First up, take full control. By default, NVDA will read its way through all of the content on the page until you stop it. I turn this off in Preferences → Settings… → Browse Mode → Automatically say all on page load.</p>
<h3 id="disable-mouse-tracking">Disable mouse tracking</h3>
<p>Next, keep things keyboard-only. I don’t like that my focus position is moved to where my mouse cursor is hovering if I accidentally nudge the mouse, so I turn off mouse tracking in Preferences → Settings… → Mouse → Enable mouse tracking.</p>
<h3 id="enable-highlighting">Enable highlighting</h3>
<p>I like to see where my cursor is, so I turn on highlighting, which places a blue rectangle around the element that I’m currently focused on. It can be a wee bit buggy sometimes when the page scrolls but I still prefer it. Activate it in Preferences → Settings… → Vision → Enable Highlighting.</p>
<h3 id="speech-viewer">Speech viewer</h3>
<p>Finally, I turn Speech viewer on in Tools → Speech viewer, which keeps a text-based log of all of the things NVDA reads out. Great in case I miss something it says, or I want to copy/paste something that it read out.</p>
<h2 id="navigation-commands-to-get-started">Navigation commands to get started</h2>
<p>Screen reader software can be noisy, so the first thing to know is how to pause it. <a href="/blog/getting-voiceover-to-shut-up">Like VoiceOver</a>, the <kbd>Ctrl</kbd> key will shut NVDA up. Aside from that, you only need a handful of commands to get around:</p>
<dl>
    <dt><kbd>↓</kbd> (down arrow key)</dt>
        <dd>Go to next thing (heading, paragraph, list item, etc.)</dd>
    <dt><kbd>↑</kbd> (up arrow key)</dt>
        <dd>Go to previous thing (heading, paragraph, list item, etc.)</dd>
    <dt><kbd>⏎</kbd> (Enter/Return)</dt>
        <dd>Follow a link, press a button, or interact with a form field</dd>
    <dt><kbd>Space</kbd></dt>
        <dd>Press a button</dd>
    <dt><kbd>k</kbd></dt>
        <dd>Go to next link (useful for links that appear inside a sentence since, unlike VoiceOver, NVDA doesn’t stop before and after a link)</dd>
    <dt><kbd>⇧</kbd> (Shift) + <kbd>k</kbd></dt>
        <dd>Go to previous link</dd>
    <dt><kbd>h</kbd></dt>
        <dd>Go to next heading (<a href="https://webaim.org/projects/screenreadersurvey10/#finding">most screen reader users use headings to find information</a> on a page)</dd>
    <dt><kbd>⇧</kbd> + <kbd>h</kbd></dt>
        <dd>Go to previous heading</dd>
</dl>
<p>Something else that will come in useful when navigating the web isn’t an NVDA command, but a keyboard-only shortcut that’s available whether you’re using NVDA or not: go back a page with <kbd>Alt</kbd> + <kbd>←</kbd> (left arrow).</p>
<h2 id="form-filling">Form filling</h2>
<p>When you move your NVDA cursor to a form field, it will be read out but, unlike VoiceOver, simply typing will not do anything. In fact, it’ll probably trigger a bunch of NVDA shortcuts that’ll navigate you all over the page, and you’ll end up disoriented.</p>
<p>As mentioned above, to interact with a form field when it has focus, press <kbd>⏎</kbd> and start typing (or, if you’re on something like a <code>&lt;select&gt;</code>, <a href="/blog/how-to-browse-the-web-with-the-keyboard-alone#select-dropdowns">use default keyboard behaviour</a> to choose an option). When finished, press the <kbd>Esc</kbd> key to go back to exit the form field and go back into ‘navigation mode’.</p>
<h2 id="take-your-time">Take your time</h2>
<p>NVDA is a powerful tool and there’s loads more to learn, but that should get you started. Screen reader usage is a very different way to use the web for many of us, and can be noisy and disorienting when you’re getting to grips with it. Patience and persistence are the key: find yourself a quiet spot where you can spend an uninterrupted hour with the software and you’ll be well on your way.</p>
<p>Not only will it give you an amazing insight into one of the many ways people use the web, but it may even offer a better understanding underlying HTML/ARIA that makes up a web page. Good luck!</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/getting-started-with-nvda">Getting started with NVDA</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>An enhancement to accessible responsive tables</title>
    <link href="https://www.tempertemper.net/blog/an-enhancement-to-accessible-responsive-tables" />
    <id>https://www.tempertemper.net/blog/an-enhancement-to-accessible-responsive-tables</id>

    
    <published>2024-08-30T00:00:00Z</published>
    <updated>2024-08-30T00:00:34Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>I’ve written about accessible responsive tables before but something has been bugging me. So here’s another step to make those tables even better.</summary>
        <category term="Accessibility" />
        <category term="HTML" />
        <category term="JavaScript" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>I’ve written about <a href="/blog/accessible-responsive-tables">accessible responsive tables</a> before, but something has been bugging me. The tables receive focus even when keyboard users don’t need them to; this happens when the container is bigger than the table and the table doesn’t scroll. As well as adding an unnecessary tab stop for keyboard-only users, the problem here is that it might leave some people wondering <em>why</em> the table is focusable.</p>
<p>So I’ve been thinking about how to make a table focusable <em>only when it needs to be</em>.</p>
<h2 id="progressive-enhancement">Progressive enhancement</h2>
<p>What I’ve got at the moment is a good baseline, and the table wrapper with <code>tabindex=&quot;0&quot;</code> is in the source code. So what I want is to remove the <code>tabindex</code> attribute with JavaScript if the right conditions are met.</p>
<p>If I were to approach it the other way round, starting without the <code>tabindex</code> attribute and adding it (together with its value of <code>0</code>) with JavaScript, there’s an outside chance the script wouldn’t run and the tables would be inaccessible. I like <a href="https://design-system.service.gov.uk/accessibility/accessibility-strategy/#progressive-enhancement">GOV.UK’s approach to JavaScript</a>.</p>
<h2 id="conditions">Conditions</h2>
<p>What are the conditions under which I remove the <code>tabindex</code>? If the table is larger that its container, it needs to be able to be scrolled, so <code>tabindex=&quot;0&quot;</code> is necessary. So I want to remove the attribute when the table is smaller than its container; this is a nice mobile-first approach.</p>
<p>Let’s start with the markup from my first article on <a href="/blog/accessible-responsive-tables">accessible responsive tables</a>:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>table-container<span class="token punctuation">"</span></span> <span class="token attr-name">tabindex</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span> <span class="token attr-name">aria-labelledby</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>caption<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>table</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>caption</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>caption<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>The title of the table<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>caption</span><span class="token punctuation">></span></span>
        <span class="token comment">&lt;!-- Table contents --></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>table</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">></span></span></code></pre>
<p>We need to do the following:</p>
<ol>
<li>Get the table’s container and its width</li>
<li>Get the table’s width</li>
<li>If the table is the same size or smaller than its container, remove the <code>tabindex</code> attribute</li>
</ol>
<p>Here’s some super basic JavaScript that does that:</p>
<pre class="language-js" tabindex="0"><code class="language-js"><span class="token keyword">const</span> container <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">".table-container"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> containerWidth <span class="token operator">=</span> container<span class="token punctuation">.</span>offsetWidth<span class="token punctuation">;</span>
<span class="token keyword">const</span> table <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"table"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> tableWidth <span class="token operator">=</span> table<span class="token punctuation">.</span>offsetWidth<span class="token punctuation">;</span>
<span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>tableWidth <span class="token operator">&lt;=</span> containerWidth<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    container<span class="token punctuation">.</span><span class="token function">removeAttribute</span><span class="token punctuation">(</span><span class="token string">"tabindex"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h2 id="multiple-tables">Multiple tables</h2>
<p>The code above only works when there’s one table on a page, but that’s a difficult thing to guarantee; what if there are two, three, or more? What we want to do instead is:</p>
<ol>
<li>List each table on the page</li>
<li>Cycle through each table in turn:
<ol>
<li>Get the table’s width</li>
<li>Get the table’s container’s width</li>
<li>If the table is the same size or smaller than its container, remove the <code>tabindex</code> attribute</li>
</ol>
</li>
</ol>
<p>Here’s some JavaScript that would do that:</p>
<pre class="language-js" tabindex="0"><code class="language-js"><span class="token keyword">const</span> tables <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">"table"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
tables<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">tableInstance</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> containerWidth <span class="token operator">=</span> tableInstance<span class="token punctuation">.</span>parentElement<span class="token punctuation">.</span>offsetWidth<span class="token punctuation">;</span>
  <span class="token keyword">const</span> tableWidth <span class="token operator">=</span> tableInstance<span class="token punctuation">.</span>offsetWidth<span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>tableWidth <span class="token operator">&lt;=</span> containerWidth<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    tableInstance<span class="token punctuation">.</span>parentElement<span class="token punctuation">.</span><span class="token function">removeAttribute</span><span class="token punctuation">(</span><span class="token string">"tabindex"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h2 id="watch-for-resize">Watch for resize</h2>
<p>One issue with my code is that the script only runs on page load. This means that if a user were to resize their browser (or rotate their iPad/iPhone 90º) the <code>tabindex</code> attribute wouldn’t be removed or re-added dynamically, so it would be:</p>
<ul>
<li>unnecessarily present for people who resize the browser up from a small, so that the tables are smaller than their container</li>
<li>missing for people who resize the browser down to a smaller size where the tables are bigger than their container</li>
</ul>
<p>I’m not bothered about the former scenario as that’s no different to how I’ve had it all these years before I added the script, but I’m less comfortable with the latter as that would leave it inaccessible. Admittedly it’s for a pretty rare scenario, where all of the following is true:</p>
<ul>
<li>The user is a keyboard-only user</li>
<li>They resize their browser from large enough to accommodate the table to where the table is larger than its container</li>
<li>The don’t resize it back to where it was before</li>
</ul>
<p>I’ll enhance the code (and update this article) at some point with a resize observer but, until then, I reckon this is a nice bit of progress.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/an-enhancement-to-accessible-responsive-tables">An enhancement to accessible responsive tables</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>User ‘wants’ versus accessibility</title>
    <link href="https://www.tempertemper.net/blog/user-wants-versus-accessibility" />
    <id>https://www.tempertemper.net/blog/user-wants-versus-accessibility</id>

    
    <published>2024-07-28T00:00:00Z</published>
    <updated>2024-07-28T00:00:35Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>When getting to grips with accessibility, there’s often a tension between what users ask for and doing things in an accessible way.</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>In organisations that are getting to grips with accessibility, there’s often a tension between what their users ask for and doing things in an accessible way.</p>
<p>The organisations in question often have that problem where:</p>
<ul>
<li>historically, they have not designed and built with accessibility in mind</li>
<li>their existing user base, therefore, does not include many/any people with disabilities since they have been unable to use the product</li>
</ul>
<p>When we introduce a change that improves accessibility, there’s often a barrage of negative user feedback that product stakeholders find difficult to ignore. That feedback usually gets to them through unfiltered Customer Satisfaction channels like online surveys, help centre enquiries, and social media, rather than via user testing sessions where a user researcher can separate user <em>wants</em> from user <em>needs</em>.</p>
<h2 id="problems-to-overcome">Problems to overcome</h2>
<p>The way I see it, there are two problems to overcome:</p>
<ol>
<li>Users’ natural discomfort with change</li>
<li>A homogenous user-base</li>
</ol>
<h3 id="users-dislike-change">Users dislike change</h3>
<p>Any change you make, regardless of the reason, is going to be met with hostility from users. Much as I hate to link to something by Jakob Nielsen after his <a href="https://www.briandeconinck.com/jakob-nielsens-bad-ideas-about-accessibility/">irresponsible and damaging comments on AI and accessibility</a>, his video on <a href="https://www.nngroup.com/videos/users-hate-change/">Users Hate Change</a> hits the nail on the head:</p>
<blockquote>
<p>Any time you release a new user interface design, you’ll get complaints. This doesn’t mean that the new design is worse than the old design; it simply means that it’s new, and users don’t like to learn different ways of doing things</p>
</blockquote>
<p>A new, accessible design isn’t just likely to be objectively better, it’s often <em>necessary</em>, but the feedback in user testing and via customer service is unlikely to be positive. Users don’t <em>want</em> change, even if they and many others would benefit from it.</p>
<h3 id="all-your-users-look-the-same">All your users look the same</h3>
<p>Your user-base is representative of who you’ve been designing for, and if, historically, your digital product team hasn’t considered accessibility you’ve defined ‘done’ as ‘it works for me’. This is because:</p>
<ul>
<li><a href="https://business.scope.org.uk/article/accessibility-and-disability-facts-and-figures">the majority of the working population is non-disabled</a>, so the majority of people who design and build digital products are non-disabled</li>
<li><a href="https://www.gov.uk/government/statistics/the-employment-of-disabled-people-2023/employment-of-disabled-people-2023#labour-market-status">Disabled people are less likely to be employed</a>, so product teams employ fewer disabled people than they should</li>
<li><a href="https://www.bbc.com/worklife/article/20211101-the-workers-keeping-their-disabilities-secret">Disabled people in employment often hide their disabilities</a>, so product teams may unknowingly include disabled people who feel they don’t have a voice</li>
</ul>
<p>Potential disabled users have been overlooked.</p>
<p>So as you begin to introduce changes that unlock your interface for people that were previously excluded, the feedback from existing users is not only going to be negative, it’s also likely to be unanimous.</p>
<p>Not only is there the natural discomfort with change, they’re also unlikely to see <em>why</em> the changes have been made, as it doesn’t benefit them.</p>
<p>The good news here is that this will change with time as a your user-base becomes more diverse, so the big issue is managing all of this unhappy users in the meantime.</p>
<h3 id="change-management">Change management</h3>
<p>The aim is to introduce changes with the minimal upset to users, and this can usually be achieved with steady, planned, incremental updates to the user interface (UI). Where this isn’t possible it may be necessary to manage the change with careful, succinct, and dismissible explanation in the UI itself, or an email or social media campaign to inform users of your drive towards accessibility and inclusion.</p>
<p>As our user-base starts to reflect the proportion of disabled people in the general population we can start to <em>really</em> understand what will make our product better; making it easy to distinguish what our users <em>think they want</em> versus what they <em>actually need</em>.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/user-wants-versus-accessibility">User ‘wants’ versus accessibility</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>WWDC 2024 roundup</title>
    <link href="https://www.tempertemper.net/blog/wwdc-2024-roundup" />
    <id>https://www.tempertemper.net/blog/wwdc-2024-roundup</id>

    
    <published>2024-06-13T00:00:00Z</published>
    <updated>2024-06-13T00:00:36Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>I got al the features I wanted from this year’s WWDC, Apple’s World Wide Developer Conference; as ever, there were also a few surprises!</summary>
        <category term="Apple" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>I wasn’t all that blown away by Apple’s World Wide Developer Conference (WWDC) this year. In fact, I don’t think I have been for a few years. It feels like their software is reaching something like feature completion.</p>
<p>That said, all I wanted this year was a <a href="https://www.tempertemper.net/blog/all-i-want-from-wwdc-2024">stand-alone Passwords app</a> and <a href="https://www.tempertemper.net/blog/if-only-apples-voice-memos-did-transcription">Automatic transcription in Voice Memos</a>. Actually, that’s not quite true; I added a late request to my WWDC 2024 wish list: <a href="https://mastodon.social/@tempertemper/112593410772187646">Extensions in web apps</a> so that I can get dark mode (via <a href="https://getnoir.app">Noir</a>) in my Google Docs web app.</p>
<p>Well, I got the <a href="https://webkit.org/blog/15443/news-from-wwdc24-webkit-in-safari-18-beta/#extension-support">web apps Extensions</a>:</p>
<blockquote>
<p>Now you can personalize web apps on Mac with Safari Web Extensions and Content Blockers. Navigate to the web app’s Settings menu to access all your installed Content Blockers and Web Extensions. Any enabled in Safari will be on by default in the web app. Each web app is uniquely customizable, just like Safari profiles.</p>
</blockquote>
<p>They also announced a <a href="https://9to5mac.com/2024/06/10/hands-on-heres-the-new-passwords-app-in-ios-18/">Passwords app, which looks great</a>.</p>
<p>Two out of three isn’t bad, but they usually release more than they announce so I thought to keep digging and… bingo! From <a href="https://www.androidauthority.com/voice-memos-transcription-ios18-3450340/">Android Authority</a>:</p>
<blockquote>
<p>The Voice Memo app in iOS 18 will be able to transcribe recordings, a feature that has been present on Google Pixel devices and various third-party apps for several years.</p>
</blockquote>
<p>So it looks like all my wishes have been granted!</p>
<h2 id="what-else-was-interesting">What else was interesting?</h2>
<h3 id="ios-18">iOS 18</h3>
<p>The updates to the Home Screen are nice: apps can be placed anywhere and app icons get a dark mode.</p>
<p>Tapbacks in Messages are no longer limited to a thumbs-up, heart, and a couple of other reactions; you can now use any emoji to react to a post. Messages can also be scheduled, which will be a good way to avoid missing sending someone a happy birthday message.</p>
<h3 id="tvos-18">tvOS 18</h3>
<p>As always, not much here, but Enhance Dialogue, where voices are amplified and background noise is minimised, is a nice accessibility feature.</p>
<h3 id="watchos-11">WatchOS 11</h3>
<p>A strange omission on Apple Watch has now been rectified: you can pause your Activity Rings in the Activity app. This allows a weekly rest day, or some time to recover from a niggling injury, all without losing your streaks.</p>
<h3 id="macos-sequoia">macOS Sequoia</h3>
<p>A couple of things specific to macOS look nice.</p>
<h4 id="window-tiling">Window Tiling</h4>
<blockquote>
<p>Users can stay organized with new ways to arrange windows into a layout that works best for them. When a user drags a window to the edge of the screen, macOS Sequoia automatically suggests a tiled position on their desktop. Users can release their window right into place, quickly arrange tiles side by side, or place them in corners to keep even more apps in view. And new keyboard and menu shortcuts help users organize tiles even faster.</p>
</blockquote>
<p>This will be more powerful than my old faithful <a href="https://apps.apple.com/gb/app/divvy-window-manager/id413857545?mt=12">Divvy</a>. Sorry Divvy!</p>
<h4 id="iphone-mirroring">iPhone Mirroring</h4>
<p>You can now use your iPhone entirely within macOS. There are lots of situations when I’m using my Mac, my phone is in my pocket, and it would be awkward to take it out to carry out a quick task; or when I’m at my desk and I’ve got my phone in <a href="https://support.apple.com/en-gb/guide/iphone/iph878d77632/ios">Standby</a>.</p>
<p>There’s something interesting about all of this device virtualisation Apple are doing: macOS runs inside visionOS too. Maybe one day devices other than Apple Vision will be redundant?</p>
<h3 id="siri">Siri</h3>
<p>Improvements to Siri are long overdue. You can now ask follow-on questions, so it’s more of a conversation, where previously it was more like a command line where you speak a self-contained instruction. Let’s just hope Siri will get better at understanding my Scottish accent…</p>
<p>I almost never use Siri in public, so <a href="https://www.cnet.com/tech/mobile/with-ios-18-i-cant-wait-to-stop-talking-to-siri-and-start-typing/">Type to Siri</a> will be useful: Double tap the app switcher bar to activate Siri as a text input, so Siri’s functionality can be used without speaking, and the responses appear in text rather than being spoken aloud.</p>
<h3 id="apple-intelligence">Apple Intelligence</h3>
<p>I’m not entirely sure about this one. All the stuff about creating images and even rewriting text feels a bit gimmicky.</p>
<p>I do like the look of <a href="https://www.apple.com/newsroom/2024/06/introducing-apple-intelligence-for-iphone-ipad-and-mac/#:~:text=The%20new%20Clean%20Up%20tool,by%20simply%20typing%20a%20description.">Clean Up in Photos</a>:</p>
<blockquote>
<p>identify and remove distracting objects in the background of a photo — without accidentally altering the subject.</p>
</blockquote>
<h3 id="some-safari-fixes">Some Safari fixes</h3>
<p><a href="https://webkit.org/blog/15443/news-from-wwdc24-webkit-in-safari-18-beta/#date-and-time-inputs">Date and time inputs will be fixed</a> for screen reader users:</p>
<blockquote>
<p>WebKit for Safari 18 beta on macOS improves accessibility support for date and time input field types. Now <code>&lt;input type=&quot;date&quot;&gt;</code>, <code>&lt;input type=&quot;datetime-local&quot;&gt;</code>, and <code>&lt;input type=&quot;time&quot;&gt;</code> elements work properly with VoiceOver.</p>
</blockquote>
<p>One final interesting <a href="https://webkit.org/blog/15443/news-from-wwdc24-webkit-in-safari-18-beta/#accessibility">titbit from the Accessibility section</a>: They’re removing the erroneous implicit <code>role=&quot;banner&quot;</code> when a <code>&lt;header&gt;</code> element is used inside a <code>&lt;main&gt;</code> or sectioning element, so we’ll be able to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/header#accessibility_concerns">use the <code>&lt;header&gt;</code> element as intended</a> without confusing screen reader users.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/wwdc-2024-roundup">WWDC 2024 roundup</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>How to browse the web with the keyboard alone</title>
    <link href="https://www.tempertemper.net/blog/how-to-browse-the-web-with-the-keyboard-alone" />
    <id>https://www.tempertemper.net/blog/how-to-browse-the-web-with-the-keyboard-alone</id>

    
    <published>2024-06-10T00:00:00Z</published>
    <updated>2024-06-10T00:00:37Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Some people use the keyboard to get around their computer. Knowing how to do this is important for accessibility testing and to inform design.</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>Some people use the keyboard to get around their computer, whether their laptop or mobile device. Knowing how to do this is important for both accessibility testing and understanding how to design and develop with keyboard-only users in mind.</p>
<p>The good news in that there are very few keys you need to use:</p>
<ul>
<li><kbd>⇥</kbd> (Tab key)</li>
<li><kbd>Space</kbd></li>
<li><kbd>⏎</kbd> (Return/Enter)</li>
<li><kbd>Esc</kbd></li>
<li><kbd>↑</kbd> <kbd>↓</kbd> <kbd>←</kbd> <kbd>→</kbd> (the up, down, left, and right arrow keys)</li>
<li><kbd>⇧</kbd> (Shift)</li>
</ul>
<p><i>Note: In this article I’m going to focus on using the keyboard to get around a web page, rather than the whole operating system (which is a bit more complex and can be activated via Settings → Accessibility → Motor → Keyboard → toggle Full keyboard access).</i></p>
<p>Page contents:</p>
<nav aria-label="Page contents">
<ol>
<li><a href="#scrolling">Scrolling</a></li>
<li><a href="#the-tab-key">The tab key</a></li>
<li><a href="#following-links-and-pressing-buttons">Following links and pressing buttons</a></li>
<li><a href="#interacting-with-forms">Interacting with forms</a></li>
<li><a href="#moving-around-items-in-a-group">Moving around items in a group</a></li>
</ol>
</nav>
<h2 id="scrolling">Scrolling</h2>
<p>The assumption is that keyboard-only user can see the screen, so how would someone move up and down a web page to read the content?</p>
<p><kbd>Space</kbd> scrolls the viewport down by about a viewport’s height at a time until it reaches the bottom, and <kbd>⇧</kbd> + <kbd>Space</kbd> scrolls it back up; again by a viewport’s height until it reaches the top.</p>
<p>In some browsers the <kbd>↓</kbd> will nudge the page down slightly, and <kbd>↑</kbd> will nudge it up again.</p>
<p>You can also jump to the bottom of the page with <kbd>⌘</kbd> (Command) + <kbd>↓</kbd> on macOS and the <kbd>End</kbd> key on Windows. The opposite is also true: you can scroll back to the top of the page with <kbd>⌘</kbd> + <kbd>↑</kbd> on macOS and <kbd>Home</kbd> on Windows.</p>
<h2 id="the-tab-key">The tab key</h2>
<p>As a keyboard-only user the tab key is your friend. It moves focus from one interactive element to another:</p>
<ul>
<li>Links</li>
<li>Buttons</li>
<li>Form fields</li>
<li>Other interactive components, such as <a href="/blog/accessible-responsive-tables">accessible tables</a></li>
</ul>
<p><kbd>⇧</kbd> + <kbd>⇥</kbd> moves backwards to the previous interactive element.</p>
<p><i>Note: by default Safari on macOS only tabs to form fields; you have to <a href="/blog/how-to-use-the-keyboard-to-navigate-on-safari">activate tabbing to all interactive components</a>.</i></p>
<p>Once you reach the last interactive element in a web page, pressing <kbd>⇥</kbd> will circle your focus back to the top of the browser. <kbd>⇧</kbd> + <kbd>⇥</kbd> from the first interactive item on a page brings focus to the items in the browser’s chrome (tabs, bookmarks, address bar, etc.).</p>
<h2 id="following-links-and-pressing-buttons">Following links and pressing buttons</h2>
<p>When you are focused on a link, pressing <kbd>⏎</kbd> follows it; the same with a button.</p>
<p>The <kbd>Space</kbd> key can also be used to press a button, although this isn’t the case with links. Pressing space when focus is on a link scrolls the page down rather than following the link.</p>
<h2 id="interacting-with-forms">Interacting with forms</h2>
<p>Things get a wee bit more complicated when filling a form in.</p>
<p>Text-based form fields like text <code>&lt;input&gt;</code>s and <code>&lt;textarea&gt;</code>s are pretty straightforward: tab onto the field, type a value, then tab onto the next field.</p>
<p>Checkboxes are even simpler: check/de-check using the <kbd>Space</kbd> key.</p>
<h3 id="radio-buttons">Radio buttons</h3>
<p>Checkboxes can exist individually or as a group (a <code>&lt;fieldset&gt;</code>), but the keyboard behaviour doesn’t change one way or the other. Radios only make sense as a group of two or more and behave differently to a group of checkboxes. Instead of being independent controls (in other words, tab to a checkbox, check it if appropriate, tab to the next, and so on) radio buttons work as a unified whole; here’s how they work:</p>
<ul>
<li>Tab onto the radio group; this highlights the first radio item but doesn’t select it</li>
<li>Press <kbd>Space</kbd> to select that first highlighted-but-not-selected radio button</li>
<li>Press <kbd>↓</kbd> or <kbd>→</kbd> to move to and select the next radio button</li>
<li>Press <kbd>↑</kbd> or <kbd>←</kbd> to move to and select the previous radio button</li>
<li><kbd>⇥</kbd> takes you out of the radio group and onto the next interactive element on the page</li>
</ul>
<p>Tabbing backwards onto a radio group where no items have been selected highlights the last item (without selecting it); tabbing or <kbd>⇧</kbd>-tabbing onto a radio group when an item has already been selected places focus on that item.</p>
<h3 id="select-dropdowns">Select dropdowns</h3>
<p><code>&lt;select&gt;</code>s behave differently on macOS and Windows. Once you’ve tabbed onto the parent ‘button’, open the menu by pressing <kbd>Space</kbd> and close it with <kbd>Esc</kbd>. Beyond that, things get interesting:</p>
<h4 id="macos">macOS</h4>
<p>On macOS you can also use <kbd>↑</kbd> or <kbd>↓</kbd> to open the menu. If an option hasn’t already been selected it will focus on the top option, otherwise it’ll highlight the previously selected option.</p>
<p>Further presses of the <kbd>↑</kbd> or <kbd>↓</kbd> keys move focus up and down the options until you hit the last (or come back up to the first) option, at which point it will stop.</p>
<p>Moving from option to option only <em>highlights</em> that option, it doesn’t <em>select</em> it. To select the option you must press <kbd>Space</kbd> or <kbd>⏎</kbd>, at which point the menu closes and the value of the parent button changes to the selected option. If you re-open the menu the selected option will have a tick next to it.</p>
<h4 id="windows">Windows</h4>
<p>On Windows, instead of pressing <kbd>Space</kbd>, you can use any of the arrow keys to change an option:</p>
<ul>
<li><kbd>↓</kbd> and <kbd>→</kbd> move to the next option until you hit the last one, at which point it’ll stop</li>
<li><kbd>↑</kbd> and <kbd>←</kbd> move to the previous option until you hit the first one, where it’ll stop</li>
</ul>
<p>When doing this, the menu remains closed and the label of the button changes. You can also open the menu first so that you can see the whole list of options; just press <kbd>Space</kbd> before using the arrow keys.</p>
<p>The big thing here is that highlighting an option <em>also selects it</em>; these are not separate steps like they are on macOS. This means that <kbd>Space</kbd> and <kbd>⏎</kbd> only have the effect of closing the menu, the same thing as pressing the <kbd>Esc</kbd> key.</p>
<h2 id="moving-around-items-in-a-group">Moving around items in a group</h2>
<p>You’ll encounter other ‘groups’ of things, for example:</p>
<ul>
<li>tabs in a tab panel</li>
<li>buttons in a button toggle</li>
<li>menu items in a menubar</li>
</ul>
<p>None of these patterns are native HTML so there’s no ‘default’ behaviour to refer to. There is some commonality though: like a radio group, the group of tabs/buttons/menu items should be a single tab stop, and the arrow keys are the mechanism to move focus from one tab/button/menu item to the next. Each item is essentially a button, so the expected keyboard behaviour would be that each button is pressed in the normal way (<kbd>⏎</kbd> or <kbd>Space</kbd>).</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/how-to-browse-the-web-with-the-keyboard-alone">How to browse the web with the keyboard alone</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>All I want from WWDC 2024</title>
    <link href="https://www.tempertemper.net/blog/all-i-want-from-wwdc-2024" />
    <id>https://www.tempertemper.net/blog/all-i-want-from-wwdc-2024</id>

    
    <published>2024-06-08T00:00:00Z</published>
    <updated>2024-06-08T00:00:38Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>There are two things I’m hoping Apple announce at this year’s WWDC, and one of them is a stand-alone Passwords app.</summary>
        <category term="Apple" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>Never mind all the hype around AI, there are only really two things I want Apple to announce as additions to their software offering at this year’s WWDC:</p>
<ul>
<li><a href="/blog/if-only-apples-voice-memos-did-transcription">Automatic Voice Memos transcription</a> (please!)</li>
<li>A stand-alone Passwords app</li>
</ul>
<p>I’ve been <a href="/blog/i-deleted-1password">using Apple’s built-in password manager for a couple of years</a> now and it has been nothing if not reliable, but every now and then I encounter a hurdle.</p>
<p>Using Shortcuts, <a href="https://www.icloud.com/shortcuts/73729e64eab14dbf99b5fd74e7e41913">I made a fake Passwords app</a>, which comes in handy on iPhone, but on my Mac I launch most apps using Spotlight so I don’t use the fake app on there. What does irk slightly is whenever I’m required to re-log in to a service in Internet Accounts; something like iCloud, my Google account, or an IMAP email account. Because Internet accounts and Passwords both live inside the same app (Settings) I have to:</p>
<ol>
<li>Open Settings → Passwords on a different device</li>
<li>Copy the password I need (which puts it in my <a href="https://support.apple.com/en-us/102430">Universal Clipboard</a>)</li>
<li>Paste it into the password field</li>
<li>Back on my other device, get the one-time code and either copy/paste it in similar fashion or just type it in</li>
</ol>
<p>Not a huge deal, but not very slick. Passwords aren’t a setting, so it’s time Apple moved them into their own stand-alone app.</p>
<p>The good news is that <a href="https://daringfireball.net/linked/2024/06/06/gurman-passwords-app">Apple might be granting my wish</a> at this year’s WWDC. Fingers crossed!</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/all-i-want-from-wwdc-2024">All I want from WWDC 2024</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Accessibility overlays are not for disabled people</title>
    <link href="https://www.tempertemper.net/blog/accessibility-overlays-are-not-for-disabled-people" />
    <id>https://www.tempertemper.net/blog/accessibility-overlays-are-not-for-disabled-people</id>

    
    <published>2024-05-11T00:00:00Z</published>
    <updated>2024-05-11T00:00:39Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Those little accessibility widgets you see on some websites are absolutely not for who you think they are.</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>An accessibility overlay (or accessibility widget) is one of those wee <a href="/blog/what-i-wish-was-in-wcag-prohibit-icon-only-buttons">icon-only buttons</a> you sometimes see floating over a web page; usually in the bottom-right corner. When you press them, they give you a bunch of options to make the website ‘more accessible’.</p>
<p>Why did I use inverted commas? Well, they <em>profess</em> to make a website more accessible, but do little-to-nothing of any real use; in fact, they can actually <em>hinder</em> a disabled user’s experience of a website! Here are some great resources that go into detail on the problems with accessibility overlays:</p>
<ul>
<li><a href="https://overlayfactsheet.com/en/">Overlay Fact Sheet</a></li>
<li><a href="https://shouldiuseanaccessibilityoverlay.com">Should I Use An Accessibility Overlay?</a></li>
<li><a href="https://adrianroselli.com/tag/overlay">Adrian Roselli’s wealth of information and documentation on overlays</a></li>
<li><a href="https://accessibleweb.com/web-accessibility-news/do-away-with-overlays/">Do away with overlays</a></li>
<li><a href="https://business.scope.org.uk/article/why-accessibility-overlays-and-widgets-do-not-improve-your-website-accessibility">Why accessibility overlays do not improve site accessibility</a></li>
</ul>
<p>Disabled people will likely already be using some kind of mechanism to make their experience accessible:</p>
<ul>
<li>browser extensions</li>
<li>features built into their browser</li>
<li>operating system accessibility features</li>
<li>third-party software the runs at the operating system level, such as a screen reader</li>
</ul>
<p>But let’s imagine a disabled visitor who <em>hasn’t</em> made any of those adjustments and doesn’t have any helpful software running. Are they likely to:</p>
<ul>
<li>notice a website’s accessibility overlay icon at all?</li>
<li>pause their task in hand to find out what the label-less button is for?</li>
<li>be able to use the overlay in the first place, without the features it offers that they need?</li>
<li>take time to configure their preferences?</li>
<li>wonder if their configuration will persist across other websites? (It won’t…)</li>
</ul>
<p>Accessibility overlays are not for disabled people.</p>
<h2 id="who-are-accessibility-overlays-for">Who are accessibility overlays for?</h2>
<p>So if not disabled people, who do accessibility overlays benefit?</p>
<p>There are the overlay companies themselves, of course, who make money every time somebody chooses to use their product. But that probably goes without saying.</p>
<p>Who else? I’m sorry to say it, but those who benefit from accessibility overlays are the people that license and install the overlay software…</p>
<p>I’m going to assume the best in those buyers; that they’re trying to do the best by their users instead of looking for a shortcut to accessibility. So, with the best intentions, non-disabled buyers pay overlay companies for a tool that <em>sounds</em> great:</p>
<ul>
<li>Protect yourself from lawsuits!</li>
<li>Achieve a baseline level of accessibility!</li>
<li>Give disabled users a better experience!</li>
</ul>
<p>None of this true. But people can be easily mislead where there’s slick sales patter and a lack of understanding.</p>
<p>Accessibility overlays are <em>for</em> non-disabled people <em>by</em> non-disabled people. The only way to properly address accessibility issues is at the product development level: carefully considered designs and well written code. Adding a single line of JavaScript to your website or app is not the answer.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/accessibility-overlays-are-not-for-disabled-people">Accessibility overlays are not for disabled people</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Images as the first thing in a button or link</title>
    <link href="https://www.tempertemper.net/blog/images-as-the-first-thing-in-a-button-or-link" />
    <id>https://www.tempertemper.net/blog/images-as-the-first-thing-in-a-button-or-link</id>

    
    <published>2024-04-23T00:00:00Z</published>
    <updated>2024-04-23T00:00:40Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>If the text of an interactive element like a button or link is preceded with an accessible image, we’ve probably got an accessibility problem.</summary>
        <category term="Accessibility" />
        <category term="HTML" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>An accessibility problem I encounter regularly is where the text of an interactive element like a button or link is preceded with an image, and the image is accessible.</p>
<p>Here’s an example of some problematic code:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>bin-icon.svg<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Bin<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
    Delete
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></code></pre>
<p><i>Note: the image could be added in all sorts of ways, from directly adding the <code>&lt;svg&gt;</code> code to using an icon font with CSS, but an <code>&lt;img&gt;</code> element makes it nice and clear.</i></p>
<p>Seems innocuous enough, but there’s a disconnect between the visible label and the underlying accessible name.</p>
<h2 id="label-versus-name">Label versus name</h2>
<p>Visually, there’s a button with a bin icon then the word ‘Delete’. Since both things in the button are accessible, a screen reader user would hear something like:</p>
<blockquote>
<p>Bin delete, button</p>
</blockquote>
<p>There are two issues here:</p>
<ol>
<li>Do screen reader users really need to hear “Bin”? Their experience is pretty noisy at the best of times, so streamlining our UI is usually appreciated</li>
<li>A hurdle has been placed in front of speech recognition users; let’s explore that some more…</li>
</ol>
<h2 id="impeding-speech-recognition-software-users">Impeding speech recognition software users</h2>
<p>In order to activate the button in our example, speech recognition software users need to say the name of the icon as part of the command, since it’s accessible:</p>
<blockquote>
<p>Click bin delete</p>
</blockquote>
<p>The first problem is that <a href="/blog/what-i-wish-was-in-wcag-prohibit-icon-only-buttons#speech-recognition-software">there’s no way to know for sure what the accessible name of the icon is</a>.</p>
<ul>
<li>“Click trash delete”? Nope…</li>
<li>“Click remove delete”? Not that either…</li>
<li>“Click delete delete”? Clutching at straws now…</li>
</ul>
<p>But most users will probably start by assuming the icon is decorative, and say “Click delete”. This won’t work either since you need to say the name of the icon.</p>
<p>People are likely to give up after the first or second attempt to press the button, and use their software’s command to attach numbers to every interactive item on the page; they’ll then just say “Click ten” (or whatever number is given to the delete button).</p>
<h2 id="how-to-fix-it">How to fix it</h2>
<p>The icon is getting in the way for speech recognition software users and adding very little other than extra noise for screen reader users. You could argue that it doesn’t really add much visually either, and you’d be right except for the fact that some people, for example dyslexic people, benefit from a visual ‘hook’ that saves them having to read the text.</p>
<p>So we want to:</p>
<ul>
<li>Keep the icon as a visual hook</li>
<li>Prevent it being picked up by screen reader software</li>
<li>Get it out of the way for speech recognition software users</li>
</ul>
<p>Easy! We just leave the icon visually and hide it accessibly:</p>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>bin-icon.svg<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
    Delete
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></code></pre>
<p><i>Note: You could also use something like <code>aria-hidden=&quot;true&quot;</code> or <code>role=&quot;presentation&quot;</code> to stop the icon being accessible.</i></p>
<p>That way screen reader users hear “Delete, button”, speech recognition software users will hopefully trigger it on the first attempt with “Click delete”, and we’ve got a text-based label together with a nice icon as a visual aid.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/images-as-the-first-thing-in-a-button-or-link">Images as the first thing in a button or link</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Alt text for CSS generated content</title>
    <link href="https://www.tempertemper.net/blog/alt-text-for-css-generated-content" />
    <id>https://www.tempertemper.net/blog/alt-text-for-css-generated-content</id>

    
    <published>2024-03-11T00:00:00Z</published>
    <updated>2024-03-11T00:00:41Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>There’s an interesting feature in Safari 17.4 that allows content added with CSS to have ‘alt’ text. I’m not sure how I feel about this.</summary>
        <category term="Accessibility" />
        <category term="CSS" />
        <category term="Development" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>There’s an interesting feature in <a href="https://webkit.org/blog/15063/webkit-features-in-safari-17-4">Safari 17.4</a>, released last week. It now supports <a href="https://caniuse.com/mdn-css_properties_content_alt_text">‘alt’ text for content added with CSS</a> (via the <code>::before</code> pseudo element and the <code>content</code> property). I’m not sure how I feel about this.</p>
<p>On the one hand it’s great because it gives developers more control over their output but, on the other hand, I question why content is able to be added to the page with CSS at all; isn’t that HTML’s job!?</p>
<h2 id="separation-of-concerns">Separation of concerns</h2>
<p>As <a href="https://medium.com/@dennis.pintilie.alexandru/separation-of-concerns-soc-fd72b0191b1f#">Dennis Pintilie Alexandru writes</a> about HTML, CSS, and JavaScript:</p>
<blockquote>
<p>each language has it’s different sections or concerns of a website … HTML … is used for the content and structure of the website … CSS … is used for the styling of the website … JavaScript … is used to define the behavior.</p>
</blockquote>
<p>In fact, Tim Berners-Lee, inventor of the HTML markup language, <a href="https://www.w3.org/Style/CSS20/history.html">always intended this to be the case</a>:</p>
<blockquote>
<p>The separation of document structure from the document’s layout had been a goal of HTML from its inception in 1990.</p>
</blockquote>
<p>I know CSS can have a pretty big impact on accessibility; to name just a few examples:</p>
<ul>
<li>the <code>display</code> property</li>
<li>use of <a href="https://www.tempertemper.net/blog/accessibility-issues-when-removing-list-markers"><code>list-style: none;</code></a></li>
<li>horribly low contrast between text and its background</li>
</ul>
<p>But adding <em>content</em> to the page with CSS is a step to far for me.</p>
<h3 id="blurring-the-boundaries">Blurring the boundaries</h3>
<p>You see, anything added to the page with <code>content</code> is accessible, and this is the issue addressed in this WebKit release:</p>
<blockquote>
<p>perhaps we want to prefix certain links with the little ⓘ icon to let users know this item leads to more detailed information. That symbol might be read by screenreader as “Circled Latin Small Letter I” or “Information source combining enclosing circle”, neither of which do a good job communicating the intended purpose. Perhaps a better experience would be to simply hear “Info:”</p>
</blockquote>
<p>The CSS example they give is:</p>
<pre class="language-css" tabindex="0"><code class="language-css"><span class="token selector">.info::before</span> <span class="token punctuation">{</span>
  <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">"ⓘ"</span> / <span class="token string">"Info:"</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>This would target any HTML with the <code>info</code> class, like this:</p>
<pre class="language-html" tabindex="0"><code class="language-html">My favourite small wild cat is the <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>info<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://en.wikipedia.org/wiki/Pallas%27s_cat<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>manul<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span>.</code></pre>
<p>Which would leave the document looking something equivalent to:</p>
<pre class="language-html" tabindex="0"><code class="language-html">My favourite small wild cat is the <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>info<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://en.wikipedia.org/wiki/Pallas%27s_cat<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Info manul<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span>.</code></pre>
<p>And the browser builds an element that has the accessible properties of:</p>
<dl>
    <dt>Name</dt>
        <dd>Info manul</dd>
    <dt>Role</dt>
        <dd>Link</dd>
</dl>
<h2 id="speech-recognition-software-users">Speech recognition software users</h2>
<p>So we’ve got a disconnect between the visual and the accessible name, which is a similar issue to using <a href="https://www.tempertemper.net/blog/what-i-wish-was-in-wcag-prohibit-icon-only-buttons">icon-only buttons</a>.</p>
<p>In our ‘favourite small cat’ example the visible label’s text reads “manul”, meaning speech recognition software users would, sensibly, say the command “Click Link label”. Unfortunately, what they <em>need</em> to say is “Click Info Link label” since the word ‘Info’ has been added to the underlying accessible name via the CSS.</p>
<p>This leaves the user with a few options:</p>
<ul>
<li>Try to guess what the accessible name is</li>
<li>Use a ‘mouse grid’</li>
<li>Show numbers next to all interactive items on the page</li>
</ul>
<p>These are all work-arounds that give our users a less than straightforward experience.</p>
<h2 id="what-if-css-doesnt-load">What if CSS doesn’t load?</h2>
<p>It’s an edge case, but possible, that the CSS fails to load; leaving the user with a <a href="/blog/css-naked-day">style-free page</a>. The good news is that this would remove the label/name mismatch issue for speech recognition software but the bad news here would be if content added via the CSS <code>content</code> property was integral to the user’s understanding.</p>
<h2 id="no-semantics">No semantics</h2>
<p>The output of anything entered in the <code>content</code> is limited to text. The example from WebKit is relatively safe from a semantics point of view as there’s no markup in there, but it’s worth mentioning that even if you add HTML in there, it’ll be output as text. So you might try to do the right thing by hiding the accessible output like this:</p>
<pre class="language-css" tabindex="0"><code class="language-css"><span class="token selector">.info::before</span> <span class="token punctuation">{</span>
  <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">'ⓘ'</span> / <span class="token string">'&lt;span class="aria-hidden"> Info:&lt;/span>'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>But that will be rendered plan text rather than HTML, so the accessible name will be <code>&lt;span class=&quot;aria-hidden&quot;&gt; Info:&lt;/span&gt;</code> rather than nothing, as we might have hoped by using that code.</p>
<p>For the record, this is the right behaviour in my opinion, but it doesn’t change that adding content to the page via CSS in the first place is problematic.</p>
<h2 id="time-travel">Time travel</h2>
<p>Of course all of that is just a whinge. Adding the alt text to <code>content</code> is the right thing to do since:</p>
<ul>
<li>the output of <code>content</code> is already accessible</li>
<li>backwards-compatibility is a <a href="https://www.w3.org/TR/CSS22/intro.html#design-principles">central design principle of CSS</a>.</li>
</ul>
<p>The <em>real</em> fix for this would be to go back in time, Terminator style, and tear up the proposal for <code>content</code> to allow anything other than decoration. Of course, that would come with its own downsides, but that’s another post in an alternative timeline.</p>
<h2 id="so-what-do-we-do">So what do we do?</h2>
<p>If you’re designing and coding responsibly, you should only be using <code>content</code> to add decorative elements to the page, meaning you’ll probably never need the <code>content</code> property’s ‘alt’ text functionality.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/alt-text-for-css-generated-content">Alt text for CSS generated content</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>The accessibility conversations you want to be having</title>
    <link href="https://www.tempertemper.net/blog/the-accessibility-conversations-you-want-to-be-having" />
    <id>https://www.tempertemper.net/blog/the-accessibility-conversations-you-want-to-be-having</id>

    
    <published>2024-01-29T00:00:00Z</published>
    <updated>2024-01-29T00:00:42Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>In most companies, accessibility conversations centre around WCAG compliance, but that’s just the start. Thinking beyond that is where you want to be!</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>For a lot of companies, accessibility conversations centre around achieving a certain level of accessibility; usually that’s something to do with WCAG (the Web Content Accessibility Guidelines) to a <a href="/blog/wcag-2-2-in-language-i-can-understand">particular version</a> and <a href="/blog/bag-some-aaa-wins-where-you-can">conformance level</a>.</p>
<p>Where I work there are lots and lots (and lots!) of digital products. All are working hard to achieve a level of accessibility, but the vast majority are not at that baseline WCAG 2.1 AA level of compliance yet.</p>
<p>Last week I was heartened when two separate conversations about two separate products were around the <em>experience</em> of screen reader users, rather than if a screen reader user would actually be able to use the product.</p>
<p><em>These</em> are the types of accessibility conversations you want to be having!</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/the-accessibility-conversations-you-want-to-be-having">The accessibility conversations you want to be having</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Screen reader users and the tab key</title>
    <link href="https://www.tempertemper.net/blog/screen-reader-users-and-the-tab-key" />
    <id>https://www.tempertemper.net/blog/screen-reader-users-and-the-tab-key</id>

    
    <published>2023-12-21T00:00:00Z</published>
    <updated>2023-12-21T00:00:43Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>People who use a screen reader on a laptop/desktop generally use the keyboard, but that doesn’t mean they use it like a keyboard-only user.</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>Screen reader users who use a laptop or desktop computer generally (though <a href="/blog/voiceovers-trackpad-commander-on-mac">not always</a>) use their keyboard to control their screen reader software. But that doesn’t mean they use the keyboard like a keyboard-only user.</p>
<h2 id="keyboard-only-users">Keyboard-only users</h2>
<p>A keyboard-only user gets around an interface with only a handful of keys:</p>
<ul>
<li>The up and down arrow keys to scroll up and down the page</li>
<li><kbd>⇥</kbd> (Tab) and <kbd>⇧</kbd> (Shift) + <kbd>⇥</kbd> to move focus from one interactive element (links, buttons, form fields) to the next</li>
<li><kbd>⏎</kbd> (Return), <kbd>Space</kbd>, and the arrow keys to interact with elements when they have focus</li>
<li>One or two other keys, such as <kbd>Esc</kbd> which should close a modal or popover</li>
<li>They’ll also type freely into text-based form fields</li>
</ul>
<p>Keyboard-only users only need to <em>interact</em> with the content on the screen, and we can assume that they can <em>see</em> non-interactive content like headings and paragraph text.</p>
<h2 id="screen-reader-users">Screen reader users</h2>
<p>With screen reader users, there’s <a href="https://webaim.org/projects/screenreadersurvey9/#disabilitytypes">no guarantee that they can see the contents of the screen</a>, so they’ll use their screen reader to access to <em>any</em> content on the screen, not just interactive stuff like buttons, links, and so on.</p>
<p>If a screen reader user were to use <kbd>⇥</kbd> to jump from one interactive element to the next they’d miss important content, so they’d use their screen reader software’s navigation shortcut keys to get around instead.</p>
<p>They’d move from one chunk of content to the next, jump from heading to heading to get a feel for the content on the page, skip straight to a particular page landmark like the footer; that kind of thing. Other than filling in form content, they’d be unlikely to use the same keys to negotiate an interface as a keyboard-only user.</p>
<p><i>Note: That’s not to say that screen reader users will <em>never</em> use the tab key; more that screen reader users will only use the it if they already know exactly what’s on the screen.</i></p>
<h2 id="manual-testing">Manual testing</h2>
<p>This is one to bear in mind if you’re doing any manual accessibility testing. Using the keyboard and using a screen reader should be treated separately:</p>
<ol>
<li>First test using the keyboard like a keyboard-only user</li>
<li>Then test with a screen reader using its build-in key commands</li>
</ol>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/screen-reader-users-and-the-tab-key">Screen reader users and the tab key</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Not all screen reader users are blind</title>
    <link href="https://www.tempertemper.net/blog/not-all-screen-reader-users-are-blind" />
    <id>https://www.tempertemper.net/blog/not-all-screen-reader-users-are-blind</id>

    
    <published>2023-11-30T00:00:00Z</published>
    <updated>2023-11-30T00:00:44Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>There’s a common misconception that everyone who uses screen reader software is blind; that’s mostly the case, but not always.</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>There’s a common misconception that everyone who uses screen reader software is blind. That’s <em>mostly</em> the case, but not <em>always</em>.</p>
<p>According to <a href="https://webaim.org/projects/screenreadersurvey9/#disabilitytypes">the most recent WebAIM Screen Reader User Survey</a> (from 2021), 79.5% of screen reader users are blind. The remaining 20.5% who are not blind may have low or impaired vision, but some may have perfect vision. Let me explain…</p>
<p>According to the British Dyslexia Association:</p>
<blockquote>
<p>Dyslexia is a specific learning difficulty which primarily affects reading and writing skills … Dyslexia is actually about information processing</p>
</blockquote>
<p>I know a lot of dyslexic people (<a href="https://www.crossrivertherapy.com/research/dyslexia-statistics">around 1 in 10 people is dyslexic</a>) and many of them use:</p>
<ul>
<li>simple text-to-speech software like <a href="https://www.naturalreaders.com">NaturalReader</a> or</li>
<li>more hardcore screen reader software, such as <a href="/blog/getting-started-with-voiceover-on-macos">VoiceOver</a></li>
</ul>
<p>This is because listening to content can make it much easier to digest than reading it on the screen; <a href="https://www.dyslexic.com/dyslexia-awareness-week-text-to-speech-software/">from dyslexic.com</a>:</p>
<blockquote>
<p>Those with dyslexia often find that text-to-speech software provides significant support if they struggle with reading or digesting text on the computer screen.</p>
</blockquote>
<p>So there you have it! Some screen reader users can see the screen perfectly well; instead of using the software to <em>access</em> content, they use it to process and understand.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/not-all-screen-reader-users-are-blind">Not all screen reader users are blind</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Accessibility by degrees</title>
    <link href="https://www.tempertemper.net/blog/accessibility-by-degrees" />
    <id>https://www.tempertemper.net/blog/accessibility-by-degrees</id>

    
    <published>2023-10-31T00:00:00Z</published>
    <updated>2023-10-31T00:00:45Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Retro-fitting accessibility is far from ideal but usually the only way digital products are able to reach all of their potential users.</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>My wife and I have fully renovated three properties in the last 20 years. The first place was the easiest; not because there was less to do, but because we were renting when we bought it which meant we could continue living in our rental flat while we did the renovation work on the new one.</p>
<p>We had a full rewire, plastering throughout, new flooring, new kitchen and bathroom; the works. It cost a fair amount of money (not to mention effort!) but we’d budgeted for it and, because were able to do it all in one go, it was relatively cost efficient.</p>
<p>Our second and third places were also fixer-uppers but:</p>
<ul>
<li>we didn’t have the luxury of renting while we did it</li>
<li>children were a factor; a toddler with our second place, and a 5 year old and a baby when it came to house number three</li>
<li>our renovation budget didn’t cover everything, so we had to decide what to do first and let our savings accumulate before moving on to the next job</li>
</ul>
<p>All this meant we had to tackle each place room by room, so it:</p>
<ul>
<li>was more expensive over-all</li>
<li>took a lot longer than blitzing it all in one go</li>
</ul>
<p>This is a lot like most (all?) web or native mobile products on their way to being accessible. Rarely do we have the luxury of a full rebuild, and most of the time we do things like:</p>
<ul>
<li>Upgrade the underlying technology (or sometimes technologies!)</li>
<li>Fix accessibility issues in the existing UI (user interface)</li>
<li>Replace sections of a monolithic product with more manageable microservices</li>
</ul>
<p>All this while continuing to give our customers those new features that they’re asking for!</p>
<p>Accessibility is expensive if it’s not considered from the outset, and a lot of companies are finding this out the hard way.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/accessibility-by-degrees">Accessibility by degrees</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Own your own content</title>
    <link href="https://www.tempertemper.net/blog/own-your-own-content" />
    <id>https://www.tempertemper.net/blog/own-your-own-content</id>

    
    <published>2023-09-20T00:00:00Z</published>
    <updated>2023-09-20T00:00:46Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Posting valuable content to social media or other platforms you have no control over can be risky; just look at the mess over on Twitter…</summary>

    <content type="html" xml:lang="en"><![CDATA[
      <p>I put a lot of energy into social media in the early days. I juggled Facebook, LinkedIn, Instagram, Twitter; it was a lot.  I quickly realised Facebook wasn’t for me and deleted my account, LinkedIn is too corporate and too self congratulatory, Instagram is full of people showing-off, but Twitter stuck.</p>
<p>For all its many flaws, Twitter worked for me. Unfortunately that’s <a href="/blog/what-has-happened-twitter">no longer the case</a>, so I packed my bags and <a href="https://www.tempertemper.net/blog/mastodon-and-me">moved to Mastodon</a>. I’ve left behind more than 17,000 tweets, which feels like a lot, but the funny thing is that I’m comfortable with it.</p>
<p>For a long time I’ve been conscious that Twitter owned the content we all posted and made a decision that, for me, Twitter was for fleeting trivialities, amusing observations, and letting people know when I’d posted to my blog. I’d never tweet anything unless I was happy to never see it again.</p>
<p>I watched as people took advantage of the <a href="https://daringfireball.net/2017/11/twitter_280">longer character count</a> and <a href="https://www.vox.com/culture/2017/12/15/16771922/twitter-new-threading-feature">threaded Tweets</a> to post much longer-form thoughts directly to Twitter, glad that any content I produced that was worth anything lived safely on my own website.</p>
<p>I won’t be using it again, but I have no intention of deleting my Twitter profile or any tweets: I’m not about to break any links to my tweets (after all, <a href="https://www.w3.org/Provider/Style/URI"><q>Cool URIs don’t change</q></a>); I’ll leave that to Twitter.</p>
<p>Meanwhile, I’ve downloaded an archive of my tweets, and one day I might get round to publishing them on a subdomain of my own site for posterity. I guess in theory Twitter could ask me to take them down but I’m a very small fish and, sadly, I doubt they’ve got the staff.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/own-your-own-content">Own your own content</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Mastodon and me</title>
    <link href="https://www.tempertemper.net/blog/mastodon-and-me" />
    <id>https://www.tempertemper.net/blog/mastodon-and-me</id>

    
    <published>2023-08-31T00:00:00Z</published>
    <updated>2023-08-31T00:00:47Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Mastodon has enjoyed a spike in popularity lately. It took me a while to wrap my head around the basic concept, but it feels like the right way to do social networking.</summary>

    <content type="html" xml:lang="en"><![CDATA[
      <p>Just like <a href="https://en.wikipedia.org/wiki/App.net">App.net</a> over a decade ago, Mastodon appeared on the social media scene a few years back as a challenger to Twitter, but it never really took off.</p>
<p>In the years that followed, Twitter went from could-definitely-be-improved-upon to pretty toxic. In order to keep my stress levels down and still get value from the platform, I set up countless mute filters <a href="https://tapbots.com/tweetbot/">Tweetbot</a>, my Twitter client/app of choice.</p>
<p>But at the end of 2022, after months of threatening to do so, Elon Musk bought Twitter and, for a whole host of reasons, <a href="/blog/what-has-happened-twitter">I couldn’t stomach using the service anymore</a>.</p>
<p>Lots of other people I followed on Twitter felt the same and Mastodon was a comfortable like-for-like switch. Cobwebs were blown off the accounts lots of us had set up back in 2016, new accounts were opened, and some people even spun up their own Mastodon server (more about that later)!</p>
<p>It didn’t take long for Tapbots, the team behind my beloved Tweetbot, to release a Mastodon client, <a href="https://tapbots.com/ivory/">Ivory</a>, making it all feel very familiar.</p>
<p>Mastodon is great, but it took me a while to get my head around a few things.</p>
<h2 id="instances">Instances</h2>
<p>Instead of being owned by one company or person, Mastodon is made up of lots of different ‘Instances’; it’s not one social network, it’s a network of them! And if you know a bit about servers you can even run your own!</p>
<p>Accounts on different Instances can interact with each other pretty much freely, so it <em>feels</em> like one service, even though it’s a federation of lots and lots (<a href="https://en.wikipedia.org/wiki/Fediverse">the Fediverse</a>!).</p>
<p>Interestingly, <a href="https://www.threads.net">Threads</a>, the new social network from Instagram, is built using the Mastodon technology, seemingly with the intention of <a href="https://help.instagram.com/169559812696339">opening it up to the wider Fediverse</a> at some point.</p>
<h2 id="rules-and-guidelines">Rules and guidelines</h2>
<p>Each Instance sets and enforces their own content guidelines, meaning you can choose the Instance that you feel most aligned to and safe with. And the good news is that if, like Twitter, your Instance changes its guidelines for the worse, you can move your account to another Instance easily.</p>
<h2 id="unusual-usernames">Unusual usernames</h2>
<p>Usernames in the Fediverse look a bit more like email addresses, where you list the Instance you’re on as well as your username, for example mine’s <a href="https://mastodon.social/@tempertemper">@tempertemper@mastodon.social</a>.</p>
<p>It took me a bit of time to get comfortable with the fact that I wouldn’t be the only @tempertemper on Mastodon: I’m the only @tempertemper on mastodon.social but there can be a @tempertemper on every other Instance.</p>
<h2 id="feels-like-the-right-approach">Feels like the right approach</h2>
<p>Without wanting to sound to grandiose, social media has changed the world; probably for the worse. A big part of that is to do with a handful of dominant platforms, each with their own content moderation philosophies that apply to an unfathomably large number of people.Impossible impossible to satisfy everyone and impossible to police.</p>
<p>A huge number of interoperable social networks, some tiny, some enormous, feels more representative of society as a whole, offering people choice and the level of protection they need. Maybe this is what social media should have been all along?</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/mastodon-and-me">Mastodon and me</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>What has happened Twitter!?</title>
    <link href="https://www.tempertemper.net/blog/what-has-happened-twitter" />
    <id>https://www.tempertemper.net/blog/what-has-happened-twitter</id>

    
    <published>2023-08-08T00:00:00Z</published>
    <updated>2023-08-08T00:00:48Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Twitter, for all its flaws, was my social media platform of choice, but since it has been taken over it has gone from bad to worse, and I’m out.</summary>

    <content type="html" xml:lang="en"><![CDATA[
      <p>Twitter, for all its flaws, was my social media platform of choice. Over the years I’ve used it to get up to the minute news about local services, won freelance work, and met people who I count as firm friends; all solely through Twitter.</p>
<p>But late last year Elon Musk, the owner of electric car company Tesla, bought the platform and I decided to take a break. Since then he has made some often deeply concerning moves:</p>
<ul>
<li><a href="https://www.nbcnews.com/tech/tech-news/twitter-changes-new-paid-verification-rules-impersonators-spread-rcna56569">Thoughtless introduction of features that would clearly never work</a></li>
<li><a href="https://9to5mac.com/2022/12/18/twitter-bans-users-from-linking-to-other-social-media-platforms-like-instagram-and-mastodon/">Suspending many people’s accounts for linking to other social networks</a></li>
<li><a href="https://www.nbcnews.com/tech/social-media/twitter-suspends-journalists-covering-elon-musk-company-rcna62032">Banning the accounts of journalists who are critical of Musk</a></li>
<li><a href="https://www.nbcnews.com/tech/internet/elon-musks-twitter-beginning-take-shape-rcna58940">Un-banning far-right accounts, including Donald Trump</a></li>
<li><a href="https://www.nbcnews.com/tech/tech-news/elon-musk-demands-twitter-staff-commit-long-hours-leave-rcna57455">Introducing a toxic working culture</a></li>
<li><a href="https://www.macstories.net/stories/twitter-intentionally-ends-third-party-app-developer-access-to-its-apis/">Unceremoniously turning off third party apps</a></li>
<li><a href="https://daringfireball.net/linked/2023/02/02/twitter-apis">Turning off access to bots</a></li>
<li><a href="https://www.wired.com/story/twitter-layoffs-accessibility/">Laid off the entire accessibility team</a></li>
</ul>
<p><a href="https://twitterisgoinggreat.com/">The list goes on</a>…</p>
<p>Incredibly, despite all of that there was the tiniest bit of nostalgia for Twitter that was keeping me from emotionally detaching completely, but last it rebranded itself ‘X’ and that’s me done.</p>
<p>You can find me over on Mastodon if that’s your jam: I’m <a href="https://mastodon.social/@tempertemper">@tempertemper@mastodon.social</a> and would love to hear from you!</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/what-has-happened-twitter">What has happened Twitter!?</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Accessibility represents maturity</title>
    <link href="https://www.tempertemper.net/blog/accessibility-represents-maturity" />
    <id>https://www.tempertemper.net/blog/accessibility-represents-maturity</id>

    
    <published>2023-07-31T00:00:00Z</published>
    <updated>2023-07-31T00:00:49Z</updated>

    <author>
      <name>Martin Underhill</name>
      <uri>https://mastodon.social/@tempertemper</uri>
    </author>

    <summary>Accessibility is a great measure of mature, disciplined software production, and Twitter have become a good example of the opposite.</summary>
        <category term="Accessibility" />

    <content type="html" xml:lang="en"><![CDATA[
      <p>I was reading <a href="https://daringfireball.net/linked/2023/07/27/crawford-twitter-x">Daring Fireball’s summary of Esther Crawford’s ‘Twitter before and after Musk’ post</a> and a paragraph on the difference between hardware/physical design and software design really stood out to me:</p>
<blockquote>
<p>Software demands more creative discipline than hardware, because so much discipline is baked into the nature of creating hardware. Hardware instills discipline in people; people must instil discipline into software.</p>
</blockquote>
<p>I’d say that accessibility is a great measure of mature, disciplined software production.</p>
<p>Accessibility, unfortunately, isn’t even an after-thought in self-proclaimed ‘move fast and break things’ organisations. They build for one group of users (and they’re not disabled users), and customer support is often the only form of user feedback they get.</p>
<p>The truth of it, though, is that accessibility actually makes it <em>easier</em> to move fast, and there’s no need to break anything! Accessibility:</p>
<ul>
<li>narrows down design choices, making the ideation much more time-efficient</li>
<li>promotes the use of a design system, which streamlines the whole design and development process</li>
<li>makes it easier for <em>everyone</em> to use an interface or complete a task, removing the need for <a href="https://webaim.org/blog/accessibility-lipstick-on-a-usability-pig/">extra work-arounds for some groups of users</a></li>
<li>opens designers up to fresh approaches to meeting user needs</li>
<li>removes a great deal of the re-work that’s necessary when the accessibility penny finally drops</li>
</ul>
<p>Twitter, where one of Musk’s first moves was to <a href="https://www.wired.com/story/twitter-layoffs-accessibility/">lay off the entire accessibility team</a>, is an example of a company that’s heading in exactly the wrong direction.</p>

      <hr />
      <p>The article <a rel="nofollow" href="https://www.tempertemper.net/blog/accessibility-represents-maturity">Accessibility represents maturity</a> appeared first on <a rel="nofollow" href="https://www.tempertemper.net">www.tempertemper.net</a>.</p>
    ]]></content>
  </entry>
</feed>
