Skip to main content

Journal

The ARIA presentation role

I’ve never properly understood when you would need to use the ARIA presentation role. This is perhaps in part because it is often used inappropriately, for example in situations where aria-hidden would be more appropriate. However I think the penny has finally dropped.

It’s fairly nuanced stuff so I’ll forgive myself this time!

You might use role=presentation in JavaScript which progressively enhances a basic JS-independent HTML foundation into a more advanced JS-dependent experience. In such cases you might want to reuse the baseline HTML but remove semantics which are no longer appropriate.

As an example, Inclusive Components Tabbed Interfaces starts with a Table of Contents marked up as an unordered list of links. However in enhanced mode the links take on a new role as tabs in a tablist so role=presentation is applied to their containing <li> elements so that the tab list is announced appropriately and not as a plain list.

Thoughts on HTML over the wire solutions

Max Böck just tweeted his excitement about htmx:

htmx (and similar "HTML over the wire" approaches) could someday replace Javascript SPAs. Cool to see a real-world case study on that, and with promising results

There’s similar excitement at my place of work (and among the Rails community in general) about Turbo. It promises:

the speed of an SPA without having to write any JS

These new approaches are attractive because they let us create user interfaces that update the current page sans reload – usually communicating with the server to get swap-in content or update the database – but by writing HTML rather than JavaScript. Developers have long wished for HTML alone to handle common interactive patterns so a set of simple, declarative conventions really appeals. Writing less JavaScript feels good for performance and lightening maintenance burden. Furthermore the Single Page App (SPA) approach via JS frameworks like React and Vue is heavier and more complicated than most situations call for.

However I have some concerns.

I’m concerned about the “no javascript” language being used, for example in articles titled Hotwire: reactive Rails with no JavaScript. Let’s be clear about what Turbo and htmx are in simple material terms. As Reddit user nnuri puts it in do Hotwire and htmx have a commitment to accessibility? the approach is based on:

a JavaScript library in the client's browser that manipulates the DOM.

Your UI that uses htmx or Turbo is dependent on that JS library. And JS is the most brittle part of the stack. So you need to think about resilience and access. The htmx docs has a section on progressive enhancement but I’m not convinced it’s part of the design.

Secondly if you have client-side JS that changes content and state, that brings added accessibility responsibilities. When the content or state of a page is changed, you need to convey this programatically. We normally need to handle this in JavaScript. Do these solutions cover the requirements of accessible JS components, or even let you customise them to do add the necessary state changes yourself? For example when replacing HTML you need to add aria-live (see also Léonie Watson on accessible forms with ARIA live regions).

Another concern relates to user expectations. Just because you can do something doesn’t mean you should. For example, links should not be used to do the job of a button. If you do, they need role=button however this is inadvisable because you then need to recreate (and will likely miss) the other features of a button, and will also likely confuse people due to mismatches between perceived affordance and actual functionality. Additionally, as Jeremy Keith has written, links should not delete things.

In general I feel the message of the new HTML over the wire solutions is very weighted toward developer experience but doesn’t make user experience considerations and implications clear. Due to unanswered questions regarding accessibility I worry that firstly they’re not natively mature in their understanding and approach on that front, and secondly that their framing of benefits is likely to make accessibility ignored due to engineers thinking that they can totally rely on the library.

I’d be really pleased if my concerns could be allayed because in general I like the approach.

Update 30/1//22

I decided to revisit a book I read back in 2007 – Jeremy Keith’s Bulletproof Ajax. I had forgotten this, but it actually contains a section titled “Ajax and accessibility”. It acknowledged that reconciling the two is challenging and despite listing ideas for mitigating issues, it admitted that the situation was not great. However since 2007 – specifically since around 2014 – WAI-ARIA has been a completed W3C recommendation and provides a means of making web pages more accessible, particularly when dealing with dynamic content.

I don’t often have cause to use more than a few go-to ARIA attributes, however here’s my understanding of how you might approach making Ajax-driven content changes accessible by using ARIA.

To do: write this section.

References:

Accessibility drives aesthetics by Alex Chen (on UX Collective)

This article is a couple of years old but just popped up on my radar again. UX Designer Alex Chen asserts that arguments which pit accessibility against aesthetics create a dangerous false equivalence… and I agree.

The article claims that if we are “too accessible” we will meet the needs of the minority but end up hurting those of the majority. This creates a false equivalence between having legitimate access needs and having a preference for a certain aesthetic.

Alex goes on to praise examples where accessibility is used to drive aesthetics – such as the Eames leg splint and GOV.UK’s design system – as opposed to considering the two ideals opposites or that one needs sacrificed for the other.

inline-block versus flexbox for horizontal arrangements

Something I’ve found interesting while reviewing recent code test submissions (within job applications) at work is that more developers than I’d expect still use display: inline-block when they need to lay out multiple elements horizontally such as the items in a navigation menu. It’s interesting because Flexbox – which has now been around for almost 10 years – gives you a modern, purpose-built solution to that.

Of course, there is no crime in taking the inline-block approach. It’s an option. And I did take a moment just to challenge my assumptions. But having given it a little thought, I am pretty convinced that Flexbox is the better approach and so I think their choice is worth a query.

Here’s why I think Flexbox is much better:

  1. Modern CSS layout is purpose-built for constructing multi-element layouts. Older methods were lacking, quirky and slightly hacky. Using (and knowing to use) purpose-built tools is generally a good thing for reliability, predictability and scalability.
  2. Modern CSS layout provides more control, because it’s fundamentally different. You get a parent context (the flex container or grid) that lets you style the context (with gap, for example). We didn’t have this before.
  3. Styling a context rather than individual items plays better with modern component-oriented organisation and ideas. It‘s good to keep components encapsulated and context-agnostic, handing off layout to separate, fit-for-purpose tools.
  4. Flexbox is built for responsiveness, i.e. built for the modern era. inline-block was not.
  5. the default align-items:stretch means that items laid out in a row are automatically full parent-height which is often desirable for larger touch targets and achieving hover styles.
  6. inline-block retains some of the properties of inline that are undesirable for this type of use-case. Who can be bothered with whitespace in the code appearing on the screen, or having to work with vertical-align when you don’t need to.

I also don’t see any reason to not use Flexbox. It’s conventional (see for example navigation menus on BBC, Tetralogical), recommended by CSS experts (Rachel Andrew, Jen Simmons etc), performant and well-supported by browsers. You are not going “fancy”, “cutting edge” or “overkill” by using Flexbox. For the “horizontal menu” use case, it’s simply a more suitable choice than the older alternatives.

Related: Chris Coyier’s article When do you use inline block is an excellent investigation into whether any necessary uses for inline-block remain. I reserve the right to change my mind on this, but aside from the “apply transform to an inline element” use case I can’t really see any that have not now been superseded.

Should I use a button or a link?

I’ve written previously about the important differences between buttons and links. While reviewing some “component refresh” design mocks at work yesterday I noticed the designs were a bit unclear in this regard so I sent the designers a little decision-tree, which I’m noting here for future reference.

It’s important both for our users and for us as practitioners to distinguish between links (the <a> element) and the <button> element. The reason I push this is because they’re fundamentally different functionally, which has important usability implications. Users expect to use mouse, keyboard, browser back-button and assistive tech differently for links than they do for <button>s. And if they can’t visually distinguish one from the other, they’ll try things they expect to work then get confused when they don’t work.

I think this is an area where design and materials can’t be considered separately and need a joined-up approach.

Here’s a flow I hope is helpful.

Ask: does it…

  1. take the user to another page? Then it’ll be a link – the <a> (anchor) element.
  2. cause something to change on the current page, or submit a form? Then it’ll be a button – i.e. the <button> element.

If it’s a link (<a>):

  • it should be underlined so people know it’s a link
  • it should have a hover state, for example stay underlined but change colour
  • in cases where it’s a CTA you might choose to design it to look button-like and remove some standard link affordances. Just be aware you’re only “calling” it a button. In real user-experienced terms, it’s still a link.
  • it does not natively have a disabled state. We shouldn’t be disabling links.

If it’s a button (<button>):

  • it should look like a button, i.e. like a pill or rectangle
  • It should not look like a link – that’d confuse users into thinking it takes them to another page.
  • So it shouldn’t be underlined by default or on hover. It should have some other hover state.

Testing the decision tree

Let’s take the example of a control for launching a modal dialogue.

The obvious choice is a button, because the control causes something to change on the current page. In this case it causes a dialogue to appear on the current page.

Some might argue that it could be a link. This is usually influenced by the fact that dialogues are often (perhaps inadvisably) used as a kind of “fake page”. And to get someone to a “page” we use a link, right? Advocates of the link option might also have progressive enhancement in mind. If they present a link either to a named fragment further down the page or to a separate page, that offers a resilient baseline experience regardless of whether or not JavaScript is available. The idea is that they also have JavaScript to enhance the link when the user’s environment supports it, perhaps adding role=button.

However a button is the more accessible and user-friendly approach for launching the modal.

Better accessible names | hidde.blog

Accessible names are used by assistive technologies to refer to elements on a web page. Hidde tells us how to word them so that they are more useful.

Because of how we use accessible names, we want to keep them functional and avoid naming controls after what they look like. Ideally, you do this in the imperative form, that makes it easiest to quickly grasp what a thing is going to do.

My summary of Hidde’s top tips is:

  • Name after function rather than form (“Open navigation” over “Hamburger”)
  • Put the most unique part first as this makes it more easy to distinguish between elements (so “Midnight Marauders - Album” rather than “Album - Midnight Marauders”)
  • Be concise – keep a name to the most important 1-3 words
  • No roles as part of the name (for example don’t include the word ‘button’ or nav. The browser already handles this part so it’d be redundant and annoying)
  • Start names with a capital letter and don't end with a full stop, because a name is not a sentence
  • Avoid ARIA if you can just use good element text content

Using the :has pseudo-class for real

By day I’m currently working on our Design System’s Table component. In order to achieve a design spec where the table has no bottom-border I needed to set:

  1. all cells in the final row of the <tfoot> to have no bottom-border; but also
  2. if there is no <tfoot> then set all cells in the final row of the <tbody> to have no bottom-border.

Modern CSS’s support for writing selectors which traverse the DOM up, down and sideways is pretty amazing here.

I’ve gone with:

tfoot > :last-child td, tbody:not(:has(+ tfoot)) > :last-child td { border-bottom-width: 0; }

(Some BEM stuff renamed for brevity but that’s the gist of it)

In the past we’ve had to bloat the backend layer with complex and awkward logic that adds “convenience classes” like .fe-Table-bodyLastRow but as Eric Meyer has been saying :has() in particular is going to remove the need for those convenience classes.

Hat-tip to Jhey Tompkins for his excellent recent article on :has which was a great help.

How to Fix Common iOS Accessibility Issues | Deque

Although I don’t work on native apps, I’ve recently been wondering about how accessibility considerations for them compare to those for websites. So this is a timely and useful reference.

iOS provides a lot of accessibility behavior for free, so it’s a great start to making a mobile application accessible. Unfortunately, accessibility is more complicated than the iOS behavior can address, and using only default behavior can actually cause the app to have additional issues.


Tabs: truth, fiction and practical measures

My colleague Anda and I just had a good conversation about tabs, and specifically the company’s tabs component. I’ve mentioned before that our tabs are unconventional and potentially confusing, and Anda was interested to hear more.

What’s the purpose of a tabbed interface?

A tabbed interface is a space-saving tool for collapsing parallel content into panels, with one panel visible at a time but all accessible on-demand. While switching between tab panels the user is kept within the same wider context i.e. the same page, rather than being moved around.

Conventional tabbed interfaces

Here are some great examples of tabs components.

Tabs are a device intended to improve content density. They should deliver a same-page experience. Activating a tab reveals its corresponding tab panel. Ideally the approach employs progressive enhancement, starting as a basic Table of Contents. There’s quite a lot of advanced semantics, state and interactivity under the hood.

Faux tabs

But in our Design System at work, ours are currently just the “tabs” with no tab panels, and each “tab” generally points to another page rather than somewhere on the same page. In other words it’s a navigation menu made to look like a tabbed interface.

I’m not happy with this from an affordance point of view. Naming and presenting something as one thing but then having it function differently leads to usability problems and communication breakdowns. As the Inclusive Components Tabbed Interfaces page says:

making the set of links in site navigation appear like a set of tabs is deceptive: A user should expect the keyboard behaviors of a tabbed interface, as well as focus remaining on a tab in the current page. A link pointing to a different page will load that page and move focus to its document (body) element.

Confused language causes problems

One real-life problem with our tabs is that they have been engineered as if they are conventional tabs, however since the actual use case is often navigation the semantics are inappropriate.

We currently give each “tab” the ARIA tab role, defined as follows:

The ARIA tab role indicates an interactive element inside a tablist that, when activated, displays its associated tabpanel.

But our tabs have no corresponding tabpanel; they don’t use JavaScript for a single-page experience balancing semantics, interactivity and state as is conventional. They’re just navigation links. And this mismatch of tabs-oriented ARIA within a non-tabs use case will do more harm than good. It’s an accessibility fail.

A stop-gap solution

If content for one or more tabpanel is provided, apply the complicated ARIA attributes for proper tabs. If not, don’t. This means we allow component consumers to either create i) a real tabbed interface, or ii) “a nav menu that looks like tabs” (but without any inappropriate ARIA attributes). I don’t agree with the latter as a design approach, but that’s a conversation for another day!

Tabs in the future

Some clever people involved with Open UI are using web components to explore how a useful tabs element could work if it were an HTML element. Check out the Tabvengers’ spicy-sections component. Again, this is based on the conventional expectation of tabs as a same-page experience for arranging content, rather than as a navigation menu. And I think it’d make sense to stay on the same path as the rest of the web.

Editable table cells

Yesterday the Design System team received a tentative enquiry regarding making table cells editable. I’m not yet sure whether or not this is a good idea – experience and spidey sense tell me it’s not – but regardless I decided to start exploring so as to base my answer on facts and avoid being overly cautious.

In my mind’s eye, there are two ways to achieve this:

  1. on clicking the cell, the cell content is presented in an (editable) form input; or
  2. apply the contenteditable attribute

In both cases you get into slightly gnarlier territory when you start considering the need for a submit button and how to position it.

I don’t have anything further to add at the moment other than to say that if I had to spike this out, I’d probably start by following Scott O’Hara’s article Using JavaScript & contenteditable.

I’d probably also tweet Scott and ask if he can say anything more on his closing statement which was:

I have more thoughts on the accessibility of contenteditable elements, but that will also have to be a topic for another day…

Update 27-09-22: I’ve also remembered that (if I were to pursue Option 1: input within cell) Adrian Roselli has an article on Accessibly including inputs in tables.