Baking accessibility into components: how frameworks help

category: thoughts

Complex components like date pickers, custom selects and modals can be tricky to get right. They can be tricky to make accessible. They need good internals, like sound semantics, keyboard usability and focus management. All well tested, preferably with a diverse set of real users. Once that is done, once a complex component is built to a high standard, frameworks or Web Components could help make that component very reusable.

Well, what’s new, you might think? Isn’t reusability of components the whole point of UI frameworks and Web Components? Yes, probably. But that is often pointed out as an advantage that increases developer convenience. I’ve heard that phrased as ‘if the developer has convenience, the user will, too’. Meanwhile, component framework-powered websites have a somewhat negative connotation among accessibility experts. This post tries to explore how component frameworks help. How they, too, can make the web a much better place for users, especially in terms of accessibility and usability. (Disclaimer: conclusions in this post may be trivial to declarative framework developers)

When I had to build a custom select

The longer a project goes on, the bigger the chance that someone will want a custom select to be built. I usually try and resist, because these are very hard to get right. Native selects have a lot of thought put into them. They work across platforms in a way that matches each platform (see native select behavior on Android, iOS). But sometimes there are good reasons. Really.

What I’m talking about, just to be clear, is not just a custom trigger (those are relatively easy), but also custom options within them. Everything custom!

The use case that initially triggered this piece of work, was a Mozilla project that had a component where someone could set field level privacy settings. There was a number of fields, like ‘First Name’ and ‘Last Name’, each with their own privacy setting. It was designed to have just the icon in collapsed state, and icons plus labels in the expanded state. An interface with all options spelled out for each field, would likely cause mental overhead. This is not a setting people set often, but we want it to be there, easy to find, because it is important to have control over your data privacy. With that in mind, it would make sense to show just an icon in the collapsed state.

No ARIA this time

ARIA is a fantastic initiative that essentially lets developers polyfill semantics. It involves adding attributes to an HTML element, in order to set accessibility-related meta information like the names, descriptions, roles and states of that element. It is specifically aimed at rich internet applications. Something to remember about it is that, while the ARIA suite adds new semantics to use in HTML, it is not a successor to the existing set of HTML elements. Those elements are still there and often very appropriate to use. The first rule of ARIA is not to use it.

Yep, it’s usually fine and appropriate to use existing semantic HTML elements.

The problem with the existing HTML element that is select, is this: browsers provide no way to customise what the options look like. But a select is not so different from a group of radiobuttons, right? Either let users pick one out of many. (I’m leaving the multiple attribute out of this, but let me just say they could map to checkboxes).

One big advantage of radiobuttons is that they are easy to customise, because you can visually hide them and then do whatever you like with their associated label element.

This is the basic version of a custom option:

<input type="radio" id="option-1" name="option-set" />
<label for="option-1">Rotterdam</label>

With this, you can apply a visually hidden technique to the input, use the <label for styling, and rely on the name to associate multiple options to be one thing. You could wrap the group of options in a fieldset and give that a maximum height. And probably a sensible (max?) width. Also, you’ll want to ensure it opens where there is space (and not outside the viewport).

Then, if your list of options is all done, there is one piece left: the thing that toggles the options. For this, I would suggest a button:

<button type="button">Choose city</button>

If you want, you could use some ARIA to convey that this button controls your fieldset. This can be done with aria-controls, with an ID as its value (use the ID of the element you expand):

    Choose city

In Using the aria-controls attribute, Léonie Watson explains that although support is inconsistent, creating a “controls” relationship in the DOM can make a component more robust, while not getting in the way of users:

The presence of aria-controls won’t damage the User Experience (UX) for people using UA that don’t support it, but it will enormously improve the UX for those people whose browser/screen reader combinations do.

Another thing you can do to the button is set the expanded state, with aria-expanded. This takes a boolean:

   Choose city

The aria-expanded needs to reflect the actual expanded state, so when the custom select is open, set it to true, if not, set it to false.

So… say, you’ve done all this work, and you start using these custom selects across your website. One risk of reusing through copy/paste is that the code ends up in many places, and only in some of the places, all the markup is used as intended. This could be detrimental to the user experience. Maybe we could actually benefit from an abstraction here.

When component abstractions aid accessibility

If we do the above and make it available as a declarative component, perhaps React, Vue or an actual vanilla Web Component, one benefit is state. As we’ve seen in the above example, there are some things that rely on state, like the setting of aria-expanded. Declarative component frameworks make such settings trivial (once you’re up and speed with using the framework, that is, we’ll get into that later).

A second big advantage, is that it becomes one whole at the point of usage. Let’s say it is called custom-select.

Whenever we want to use custom-select, we do (pseudo code):

<custom-select options="options" />

In which options is some JavaScript object of options.

We declare it, we say what the options are, and in the DOM, it becomes a custom select with those options. This “becoming a custom select” might worry front-end folks, but it is not some sort of magic. We have described exactly what this means, how it should be done. With which semantics, keyboard behavior, focus styles and usability. These things are very important metrics for quality, they require careful consideration. The advantage of using some sort of component abstraction is that only one person or one team has to do this thinking. Others then ‘just’ use it, without worrying about the internals.

In my case, I’ve gone for a button that toggles a fieldset, but if there is a better way, custom-select can become whatever that better way is in the future. We need to come up with excellent internals, even be ready to improve them after a user test or accessibility. But all in all, I find this separation between internals and actual usage helpful.

A good example of a similar separation of concerns, from existing HTML, is the <video> element. It has a couple of internals that developers don’t need to worry about at the point of usage. We just need to tell it where our video and subtitles live. It then deals with internals for us: play buttons, closed captions, even multiple video formats… all the good stuff.

I’m more and more convinced that containment of ‘the good stuff’ can make the web better for users.

Increased complexity

There is a disadvantage to this nice containment of components using a framework: it’s complex. I mean, the tooling required to ship code is, because it requires advanced knowledge of JavaScript. That potentially scares people away. Complexity could reinforce privilege and moving all of a component into JavaScipt can turn full-stack developers into gatekeepers. Heydon Pickering describes there is a problem with full stack:

if you put someone in charge of all [the full stack], it’s highly likely they are going to be much weaker in some areas than others

In his post, Heydon identifies that what I call a component’s “internals” above are often built poorly. For two reasons: because improving internals now requires knowledge of complex frameworks and because the people specialising in them get undervalued. People who are good at writing front-end code that improves accessibility, but not at advanced JavaScript, might give up, at which point the web could lose out on accessible functionality. That’s sad.

I really like working on the detailed stuff that affects users: useful keyboard navigation, sensible focus management, good semantics. But I appreciate not every developer does. I have started to think this may be a helpful separation: some people work on good internals and user experience, others on code that just uses those components and deals with data and caching and solid architecture. Both are valid things, both need love. Maybe we can use the divide for good?


Modern websites commonly contain complex interaction patterns that aren’t default on the web. We may dislike that or prefer simplicity, but that’s a different (and also interesting) discussion. If we are going to code these complex interactions, it makes sense to contain the result in a component. Let’s assume we’ve worked hard on very accessible and usable ‘internals’, ran user tests and are confident that they are good. Then re-usability is a great thing, because the people who reuse, don’t need to worry about the internals. Like they wouldn’t worry about the internals of a video element when they use that. This is how I think frameworks can help make the web more accessible to users. And, ultimately, pave the way for more user convenience.

Update 31/1: In this post, I regard framework components and Web Components as one group for lack of a better word, but as Šime Vidas notes in the comments: if we make accessible components it makes more sense to do it in framework-agnostic Web Components than in a framework. To add to that, it might not only be tool-agnostic, but also more future proof.

Comments & mentions (47)

Gift Egwuenu ✨ reposted this
Gift Egwuenu ✨ likes this
Eka likes this
Koen Kivits likes this
Satya Kresna likes this
ioana likes this
Anneke Sinnema likes this
Joshua Marshall likes this
Marco Zehe reposted this
Rhian van Esch reposted this
Rhian van Esch likes this
Daniel Mclaughlan likes this
Marc Stalfoort likes this
Mardav Wala likes this
Jan Hoogeveen replied: Preach it brother!
Jan Hoogeveen likes this
Michelle Barker likes this
Adam Silver replied: Nice post, Hidde - with the <custom-select> web component you mentioned, what's the "no js" fallback?
Hidde @ CSSConf / JSConfEU replied: very good question! there's none, this exists in a ‘requires JS’ world, I'm afraid
Michael Hastrich reposted this
Filip Danisko likes this
Giovanni Morelli likes this
Šime Vidas replied: Frameworks can make their controls accessible (and they should), but wouldn’t it be better if we instead focused on standalone, framework-agnostic web components for these custom controls that are relatively common but aren’t (yet) standardized in HTML?
Sibelius Seraphini likes this
Hidde @ CSSConf / JSConfEU replied: yes! Yes, absolutely.
Harry Cresswell likes this
likes this
Hans de Bruin likes this
Ruben Duiveman likes this
Ingrid replied: Good article about accessibility…
Yohan J. Rodríguez replied: #CSS #Automated | Baking Accessibility Into Components: How Frameworks Help…
Thomas Steiner replied: Great article by @hdv ⤵️. Open question: what’s the recommendation regarding making custom element focus behavior look “native” when all we have (as far as I know) is `-webkit-focus-ring-color`?
CC: @rob_dodson…
Yohan J. Rodríguez replied: #WebPlatform #Automated | Baking Accessibility into Components…
Trevor Pierce replied: Baking accessibility into components: how frameworks help…
Jeremy Keith replied:

Baking accessibility into components: how frameworks help

A very thoughtful post by Hidde that draws a useful distinction between the “internals” of a component (the inner workings of a React component, Vue component, or web component) and the code that wires those components together (the business logic):

I really like working on the detailed stuff that affects users: useful keyboard navigation, sensible focus management, good semantics. But I appreciate not every developer does. I have started to think this may be a helpful separation: some people work on good internals and user experience, others on code that just uses those components and deals with data and caching and solid architecture. Both are valid things, both need love. Maybe we can use the divide for good?

Adactio Links replied: Baking accessibility into components: how frameworks help…
Jeremy Keith replied:

Glad to hear that this common use-case is getting “standardised”:

Erik Kroes likes this
Phil Thompson likes this
CSS-Tricks replied:
I am also optimistic that the concept of components can ultimately be a way to broadly _improve_ accessibility. ...…
Marco Zehe reposted this
Ethan Marcotte likes this
negi4a likes this
Unknown replied:
Marcus Herrmann likes this
Jan Skovgaard likes this
Hidde de Vries (@hdv) is a freelance front-end and accessibility specialist in Rotterdam (NL), conference speaker and workshop teacher. Currently, he works for the W3C in the WAI team (views are his own). Previously he was at Mozilla, the Dutch government replied:

Wow, the year only has 8 days left! Time for a review.

Like last year, I’ve divided this into highlights and things I learned.



In the first half year of 2019, I continued my project at Mozilla’s Open Innovation team, building their People directory, and worked in the City of The Hague on accessibility and the internal design system.

In July I started a new project: at the W3C’s Web Accessibility Initiative (WAI), I am now working as part of the European Commission-funded WAI-Guide project. My work there is focused on improving the accessibility of/in tools that create web content, like CMSes. In short: we want more accessibility both for content editors (a good editing experience) and for end users (good output).

Apart from my work at the W3C, I’ve been doing the occasional WCAG audit and accessibility/CSS workshop in my own capacity too.


Last year I spoke at my first conference. This year I got the opportunity to do new (and some older) talks in various places.

In March, I did a talk called It’s the markup that matters at De Voorhoede. It was part of their Future Proof Components event, and covered building accessible components, accessibility trees and the AOM.

At WordCamp Rotterdam and Inclusive Design Ghent, I shared 6 ways to make your site more accessible, based on my experience looking at common accessibility problems that front-end developers can do something about.

In October, I presented a very short lightning talk at the Web We Want session at View Source Conference, about how some accessibility problems could cease to exist if browsers would automatically fix them. The problems: zoomability, readability, color contrast and focus indication (the first three are each solved in at least one browser, the fourth has not). This talk, shockingly, won both the jury and audience award.

Also in October was a talk called Breaking barriers with your CMS at the Fronteers Jam Session (on behalf of W3C/WAI). This presented some of my recent work at WAI: it explained ATAG and the role of the CMS in accessibility efforts.

At the Design in Government Conference in November, I talked about the case for web accessibility from philosophical ethics, attending on behalf of W3C, and I did an updated version of my graphic design on the web talk in Dutch for Freshheads in Tilburg.

Then in December, I joined dotCSS to talk about the history of CSS: On the origin of cascades put some of that in a Darwin-themed talk. The venue was enormous and intimidating, and there was transport strikes, but the event itself was excellent, with a great atmosphere and very well organised.

I also did a number of in-house talks and workshops, about CSS Layout, ARIA and accessibility guidelines.


I read much more than last year (72 books so far), and have written more about books on this blog (see reading list about equality and reading list about tech and society). Reading more books helped me read less social media, watch less video and generally relax more.

Some notes:

  • Audiobooks are great as you can read them in situations where holding a book doesn’t work (e.g. walking a dog, housework)
  • To read more, finding the right books is half of the work (I mean, not literally… but it is important). I found more people to follow on Goodreads, keep a close eye on the literary supplements in the papers and love posts like 2018: books in review by Karolina Szczur.
  • Dutch libraries have ebooks and audiobooks that can be ‘borrowed’ via apps.


This year marked over 100 posts on this blog, I wrote 24 posts (including this one).

Some posts that people found interesting:

I also contributed to the Mozilla Hacks blog, writing Indicating focus to improve accessibility and How accessibility trees inform assistive tech. Thanks to Havi Hoffman for the opportunity!


This year I traveled to Antwerp, Berlin, Bristol, Essen, Ghent, Nice, Paris, Taipei and Vienna, using trains where possible, but I need to do better at that.

Things I learned

Here’s some random things that I learned about in the past year:

  • Recently I started working on an app with Svelte, the front-end framework that doesn’t ship in its entirety to the user’s runtime, but tries to compile as much as possible to vanilla JavaScript. Small bundles, yay!
  • As I started my project at the W3C, I learned a lot the standards process, the dynamics in Working Groups and the bots that help run teleconferences.
  • A large part of my work centered around authoring tools, or tools that create web content, and how they can help bring more accessibility in the world.
  • I became increasingly aware of the role of surveillance capitalism in the world.
  • I learned to love AirTable as a way to organise and plan the non-coding parts of my work, which are becoming a larger part of the whole

In any case, I’d like to thank the readers of this blog for reading and sharing the posts I’ve published, it means a lot. I wish you all a great 2020!

Leave a comment
Posted a response to this?

This website uses Webmentions. You can manually notify me if you have posted a response, by entering the URL below.