Intro
Hello JSConf! Tejas was absolutely correct, this talk is about HTML.
A presentation at JSConf Budapest in June 2022 in Budapest, Hungary by Hidde de Vries
Hello JSConf! Tejas was absolutely correct, this talk is about HTML.
So in the next 30 minutes, sorry to disappoint, unlike Lucky, I won’t be flying drones with bananas… that was a great talk wasn’t it? I will also not hide gorillas in these slides, as Moran did, or combine the history of art with the awesome possibilities CSS has today, like Nils… instead this talk will be about HTML and what it can do, for you and for your users.
HTML is awesome, because it enables lots of things.
It enables a multi device web… we use CSS to create experiences that work across device and viewports and what not… the reason we have a structure to program our CSS against: HTML!
HTML enables browsers to come with sensible defaults. Maybe your project uses a CSS reset, but there’s likely still styles that are set by the browser, like table styles to make stuff appear next to other stuff, and all sorts of other things, have you ever stared at the computed styles in dev tools?
There’s browse by heading, which I’ll get into in a minute.
Default behaviors are enabled by HTML, so like buttons would submit a form by default and the browser knows to do that because HTML exists.
Or reader modes… which are essential for people with certain disabilities and nice for us all, on today’s web that gets more and more complicated over time.
Ok, so my talk is called It’s the markup that matters, I guess that won’t surprise you now. Let me tell you why over the next 30 minutes!
First, I haven’t introduced myself, I am Hidde, i do dveloper relations at Sanity. We’re on a mission to make content easier to work with for content creators, developers and even businesses… the end goal is more delightful, remarkable digital experiecnes. In recent years I also did a lot of accessibility work, most recently at the World Wide Web Consortium, promoting web standards for accessibility. And I blog, you can like and subscribe at hidde.blog, or follow me on Twitter, I’ll post my slides there too.
So let’s talk about accessibility.
In its simplest form, web accessibility is all about ensuring people with disabilities can use your site or app.
Or, to phrase it differently… it is to ensure they can buy your product.
Or use your service.
Yesterday there was this show of hands around who is or knows people with a disability… the stats don’t lie, many of us have disabilities, in many shapes and forms, from neurological conditions to motor impairments.
Like, a lot of people use high contrast modes.
Or zoom in on websites, which low vision users do to access the content.
Some people prefer reduced motion as motion could make them sick, literally.
Lots of people don’t use a mouse, for a variety of reasons… they might be using a switch control or use their voice or use a keyboard.
So, many things to optimise for, which is why everyone in the team has some accessibility responsibilities. But today I want to focus.
Today, I want to focus on specifically people who use assistive technologies, as that’s the part where code and developers make a huge difference.
It’s tech like voice control that lets users control their computer by voice, switch controls, braille displays that translate what happens on the screen into braille in real time and screenreaders. All of this tech exists so that people can use computers and the web in a way that works for them.
Our markup hugely impacts the user experience, let’s look at how.
When someone accesses your site, let’s say they type in a URL and press enter, your server is going to respond with markup. The browser turns that into a DOM tree.
From the DOM tree, the browser creates a secondary structure called the accessibility tree. It has things like here’s a radio button called ‘Round trip’ that you can press and it is selected, a slider that can go from 0 to 24 and it is set to 7, it’s called ’Departure time’ and you can increment and decrement it. A button that is called ‘Search’ that can be pressed. By now you may be able to visualise some kind of UI that allows users to do the things defined here in the abstract. Assistive technologies do this too, but they use interfaces specific to their user group.
Example of an Accessibility Tree (image of description above)
For each accessibility-relevant DOM node, accessibility trees have information on what kind of thing an element is, like is it a button or a link, or a text input… that’s called the ‘role’. There is info on how to refer to it, these are the name and description, stuff like this button is called ‘Save details‘ or that slider is ’Departure time‘. And then there is some more meta info like is this thing selected or checked or expanded.
When I audit a website for accessibility, I’ll be looking for this sort of information. Among other things. So if I see a website has a bunch of links, I’ll go and check…
Oh cool, this one has a role of link, name is “World”
another role of link, with the name “US politics”… ok let’s skip that one for now.
then there is a role of link with the name “Business”
and a role of button with the name of “Edition”. I guess I can find different editions of CNN dot com there.
So as mentioned, our markup informs the DOM tree, out of that the accessibiliy tree is constructed, that’s the story so far. From there on, information is passed to so-called Platform Accessibility APIs that are built into all the major platforms, Windows, Mac, Linux, mobile OSes… and then from those APIs, ultimately the assistive tech is informed, and with that, the user. So, our markup matters, it impacts the AT, ultimately.
You can look at accessibility trees in all major browsers, there are tabs available and popups that show up when you inspect elements. If it mentions roles and names and states you now know what they are.
Ok, so what does that look like in practice?
Let’s look at some examples… and don’t worry, the following examples work with all of your favourite tools)… whatever generates your HTML for you, it’s all going to go into that same DOM and interpreted the same way. All tools are welcome here.
One question markup answers is “Where am I?” When a screenreader user arrives on your page, they will hear what’s inside your ‘title’ element.
This is often an element that is somewhere in a template we never go… but this means it’s super important to keep it up to date and have a fresh title for each page, including in single page apps, where you might need to update this on route.
Code example: <html lang=”nl”> <head> <title>It’s the markup that matters Presentations - My site</title> </head> <body> … </body> </html>
A cool video about this is on Smashing TV with my friend Léonie Watson, accessibility expert and screenreader user, who explains that the title confirms to her that it is the page she intended to reach.
Another question markup answers is “What is on this page?” It’s done with headings.
So whenever you use <h1>, <h2>, <h3>, people can see headings in reader mode, but also they can navigate by heading. Most screenreaders have a way to access headings of a page, and it lets jump people directly to that heading, so it’s a way to find content fast. It’s a bit like when you call a customer service and they say something like “Press 1 for support, press 2 for sales”, but based on your headings on your website.
For this reason it’s so important to ensure the headings are well written.
Another question you can answer with markup is: which areas are on this page? Like, remember yesterday when the organisers started explaining the venue and pointed out there are toilets, community lounge, sponsor booths, et cetera
With landmarks in HTML you can do that sort of thing but for your page.
HTML has some elements built in that are landmarks natively, if you use them in your code you are basically establishing a landmark.
There’s a great article about using landmarks carefully and what to look out for called “Accessible landmarks” by Scott O’Hara, recommended reading if you want to get started using landmarks. One takeaway from this post is that you shouldn’t use too many. Thinking about the venu here, you wouldn’t want the organiser to point out every single chair in this hall, that would not be a meaningful thing to do.
Landmarks are currently only available in screenreaders. I’m going to embarrassingly quote my own presentation here… I did a talk a few years ago about what browsers could do about accessibility and one of the things I proposed there was browsers to expose landmarks so that sighted users could use them too. I’d still love to see that!
Ok, let’s move to form controls. There is a ton to say about them in terms of accessibility, I’ll focus on just one today, which is the accessible name. There’s this non profit called WebAIM in the US who look at the accessibility of the top 1 milion websites every year.
In the 2022 survey they found almost half of the websites they looked at had unlabelled form fields.
So, form fields like inputs, radio buttons, checkboxes, selects, textareas etc need to have labels, it gives them an accessible name in the accessibility tree.
Let’s say you use this code to write an input people can put their city into:
<div class=”form-item”> City <input type=”text” /> </div>In the accessibility tree it is going to show up with a role of ‘textbox’ or ‘entry’ and a name of null or empty string.
Browsers have lots of ways to figure out what an input is called, to find the name, this is all specificied in a name and description computation specification… find the link for more details on that.
For now, I’ll give you one way to do it, which is to add a label element around the word ‘City’ and then relate it to the input using a for attribute on the label that corresponds with the id of the input.
Now the accessibility tree computes a role of ‘textbox’ / ‘entry’ and a name of ‘City’.
Code:
<div class=”form-item”> <label for=”city”>City</label> <input id=“city” type=”text” /> </div>Then I’d like to mention table semantics.
There seems to be an urban myth that tables are bad for accessibility, but they are actually a great way for users to navigate tabular data.
One thing to look our for, though, is to make sure to add headings and set a scope. And in terms of naming, it’s often useful to add a caption element, which has to be the first child of the table.
A caption can be used to distinguish multiple tables on a page, like if you have this financial documents page, and I’m obviously not in finance, but let’s say you’ll need to distinguish between different tables, say one is for 2018 and another one is for 2019, you’ll want to add those unique names into the caption element. This way, users of screenreaders can find the tables more easily and when they find them, ideally know at once if they’re the one they are looking for.
The last element to discuss is buttons.
They are awesome! I know in some teams buttons are replicated by divs, but it is actually really hard to build a good button out of a div. Buttons come with lots of stuff built in, like you can find it in tab order, it works with a keyboard and it can even submit forms with the default button type.
Now what about the names of buttons? This is easy-ish when there is text, the text becomes the name, basically. But what if you buttons have just icons?
In markup it may look a bit like this. Inside of your button element, you may have some svg content. It’s a shape but the browser doesn’t know of what or what to do with it, so it is going to compute the accessible name to null.
Ways to fix that include adding an aria-label attribute to the button element, with as the value the name you want. This will override any contents this button has in terms of name computation, so if you had any text in there, it will be discarded and the aria-label value will be the name. Note that there have been bugs in browsers around translating this part when putting a page into Google Translate, so that’s a bit of a downside.
Another way to do it is to add actual text inside of the button. You can make it invisible with a so-called visually hidden class, sometimes it is called ‘visually-hidden’, sometimes also ‘sr-only’, the main thing is not to use display none or visibility hidden as that hides content from the accessibility tree as well, so these visually hidden techniques use CSS that preservces the content, like position absolute.
I hope by now you are all excited about the powers of HTML. If you want to know in much more detail how to use specific elements in HTML, developers.whatwg.org is a great place, it is basically the specification that browsers and other user agents also use, but with the browser specific stuff taken out.
Another great website about using HTML is HTMHell by my friend Manuel Matuzovich, this page collects examples of what went wrong with explanations of how it went wrong.
Ok, so we’ve looked at how to use markup for accessibility support, but as we’re at a JavaScript conference I thought it would be good to look at some work in progress around taking some of this stuff to JavaScript land. The Accessibility Object Model effort happening in a W3C community group works on exactly this.
They aim to “develop additions to the web platform to allow developers to provide information to assistive technology APIs, and to understand what information browsers provide to those APIs”, says the AOM explainer document. Note these are mostly proposals, we’ll talk about some of the plans that are being discussed.
The first one is actually suported in both Chromium and Safari and it is the ability to set accessibility properties like roles and states as so called IDL attributes, so rather than using a setAttribute on the element you assign directly to a property. It has the same effect though and will reflect in the DOM tree and can be changed there.
Code: const el = document.querySelector(“el”); el.role = “button”; el.ariaDisabled = false;
When you’re building Web Components, you may want to “bake in” accessibiltiy properties to your components though. In recent Chrome Canary you would be able to set this through ElementInternals, eg you would set _internals.role on an element to set the role.
IDREFs are important in HTML as they can establish relationships between elements, like in the example I showed of where a <label> tag is related to an <input> in order to provide it with an accessible name. There are many relationships like that in ARIA too. The AOM folks are looking at assigning such relationships directly, so you would do something like element.ariaDescribedBy = someOtherElement. This isn’t supported anywhere yet.
One reason this is being explored, I believe, is that IDREFs don’t work across Shadow boundaries in Web Components. There is some early discussion on a “cross-root ARIA Delegation API”, the explainer is on github.com/leobalter/cross-root-aria-delegation/blob/main/cross-root-aria-delegation.md.
It would be, quoting the explainer, “an API to forward ARIA attributes and properties set on a Web Component to elements inside of its shadowroot”.
The original AOM discussions also included plans to include events from Assistive Technologies, so that you could, as a developer, get events for things like this Voice Control system clicked on a button. But like it has accessibility built in, the web has privacy built in, and there were privacy concerns.
The current proposals describe, instead of events from Assistive Technologies that would expose a user’s disability, synthesised DOM events, so a click event would get generated for an assistive tech click, and your code wouldn’t know if had come from an assistive techology or a mouse click. It works like this in many cases already, the AOM group are documenting some of this to make sure all the different cases align with actual behaviors.
The last part of AOM proposals is the idea of reading the accessibility tree from JavaScript. You could already find out stuff with JavaScript now, like you could read getAttribute(‘aria-label’) to see what name it tries to set, but this would give you access to what the browser has actually computed as role, name or other property. This is great for tests! This is available in Firefox and Chromium today, though with an outdated syntax.
Ok, so far we’ve looked at setting accessibility meta information by using HTML and JavaScript… before I leave you, let’s talk a bit more about doing accessibility through HTML.
As Tiger showed yesterday, using the power of the web platform can lead to great things! This goes for HTML too, HTML comes with accessibility built in… I mean, in lots of sense, like the image and video tags have features to provide text alternatives, most form controls come with accessibility features like semantics and keyboard behavior. I love this.
But… there isn’t HTML for everything! We don’t build websites with just some headings, lists and form elements.
I mean, some of probably have been through the pain of building a custom calendar widget? This sort of thing isn’t really there in the web platform… there is an input type of date, but it is tricky or impossible to customise and brand.
There are a bunch of elements in HTML that never needed to be styled, but it seems like today a lot of web developers are using a lot of their time customising UI controls, or building them from scatch. At least that’s an observation Nicole Sullivan (at Google) and Greg Withworth (at Salesforce, previously at Microsoft) had. They started an initiative called Open UI to work on this problem.
Open UI wants to make it unnecessary to reinvent built-in UI controls. The group works on features for the web platform, be it APIs, new HTML elements, attributes, CSS features, that all try to make it easier to build UI patterns with less effort for developers, leaving more to the browser.
I’ve been in this group for a bit of a year… I mean, I’m not a browser maker or pro spec writer, but I’ve been attracted to these meetings and discussions, wanted to follow along, because I believe in what this effort could achieve.
I think standardised controls can be a huge opportunity for accessibility. I was chatting to someone yesterday who worked on a design system and we talked about the huge ripple on effects these things can have… you build a component badly and the badness propagates everywhere… you build it well and the goodness propagates everywhere. More standardisation around browser controls, if done well, could end up propagating a lot of accessibility features towards end users.
Not easy though… Nicole Sullivan tweeted about this last month, a goal is to try and have “implied accessibility semantics”, to have accessibility “handled for common use cases”, it would be chef’s kiss… but, she says, this is hard. I agree with that, from the discussions we’ve been having at Open UI, there’s a lot of considerations and sometimes they conflict. Long story short, there’s a bunch of people working in different settings to try and ensure many accessibility considerations are met.
I want to share two different things that we are working on at Open UI. One is the selectmenu tag.
Has any of you built custom selects before? Greg Whitworth surveyed developers and asked how they liked styling select tags.
Responses included:
Source: Greg Whitworth, Can we please style the <select> control?
So if you were to build a regular select, you might do something like:
<select> <option>Tabs</option> <option>Spaces</option>
<option>A mix of both</option> </select>and it looks however the browser decides to.
With the new <selectmenu>, you would do pretty much that, in its most basic form, but replace select with selectmenu. Now you can do things like replace the HTML of some of these contents, and, what I want to show you today, style the individual pieces as if you were styling divs.
So you could style h button by selecting selectmenu::part(button)
in CSS and applying styles, like background-color: #f00; border-radius: 5px;
You could style the listbox with selectmenu::part(listbox)
.
Or the selected value with selectmenu::part(selected-value)
.
The cool thing is, you can play with it today if you have Chromium or Edge Canary and turn on the Experimental Web Features flag. Note there are known accessibility issues and all of this is subject to change. Do try this at home, just not on a public facing websites, basically, just yet.
The second element I want to highlight is really an attribute, this recently changed. The popup attribute would let you make popup like interfaces.
At Sanity, we have a component to upload images and it comes with an action menu with some image related actions, like Copy URL and Replace. This sort of thing could be built as a popup in the future.
And action menus is just one example of popup-like behavior, others are teaching UI, content pickers such as date pickers, form element suggestions and, as just discussed, selects.
What popups have in common is that they are on top of other content, that they are ‘ephemeral’, like, temporary, they’re only open when they need to be, otherwise closed. And there’s usually one at the time.
Ok, so let’s look at what the markup for that would look like. Again, this is all still in development, but this is what it would work like according to current proposals.
So let’s build our image action menu. We’ll create a div with inside of that a heading and two buttons.
Then we’ll add the popup attribute to the outer div. This turns it into a popup, meaning the browser will be closing (or really, hiding) it by default. If it needs opening, you’ll be able to call a showPopup method in JavaScript. Or, and I love this, add the open behavior declaratively.
Code:
<div popup> <h3>Replace image</h3> <button>Upload</button> <button>Browse</button> … </div>Let’s add an ID for that, we’ll add id=options to the div.
What we can do then, and here’s the IDREF again, refer to the popup from a button, by setting a togglepopup attribute on the button, with the ID of the popup as its value.
Code: <button togglepopup=”options”> Image options </button>
<div popup id=”options”> <h3>Replace image</h3> <button>Upload</button> <button>Browse</button> … </div>When we added the popup attribute, we were using popup’s auto mode. Having just the popup attribute is equivalent to doing popup=auto, it is the most popup-y popup.
Another type is popup=async. An example of that would be… at Sanity, when you publish a document, stuff happens on our content servers and if all goes well, a notification, ‘toast’ type of element appears that says the publishing was successful. This is the kind of thing you could use popup=async for.
It’s still under discussion whether this should be a live region by default, so that an announcement of the newly appearing content is made in a screenreader, for the time being we could wrap this popup in a div with a role of alert.
So, if we have a div with popup async, we can leave that empty until we know the content. In JavaScript, we first find the element.
Then, whenever we’re in the success state, for simplicity I’ll leave all of that out, that’s for another talk, let’s say the upload was successful… we basically update the content of our ssync popup and call the showPopup
method on this element.
Like <selectmenu>
, popup
is available in Chrome and Edge Canary, you can go play with it.
If you do, we want your thoughts! One way to get involved is to follow @OpenUICG on Twitter, tag along on Discord or even join the meetings, they are open to all, if you’re a developer building UI components your input is very much valued.
Ok, so, let’s wrap up!
Today we’ve looked at the ways HTML can and will affect your user’s accessibility trees. If you want it or not, these trees are constructed based on your markup and you can impact the info that ends up there, ensuring names, roles and states are what they should be.
Excitingly, there is some work happening in the AOM group on allowing some accessibility meta information to be controlled and read from JavaScript land.
And, maybe, if things go well, we’ll get more markup, attributes, APIs, CSS features that will make it easier to build components that have accessibility built in. Even if that’s hard, I’m super excited about this, it’s a promising future!
And that’s all for me today, thanks so much again for listening!
You can find these slides on talks.hiddedevries.nl, follow me @hdv or email hidde@sanity.io.
Special thanks for clarifications, input, feedback Mason Freed, Scott O’Hara, Julia Silver, Eric Eggert, all at Open UI CG
Typefaces in the slides are Bungee by David Jonathan Ross (DJR) Rasa by Anna Giedryś, David Březina (Rosetta)