The web industry is unlikely to ever stop building custom UI components, which is fine. But the web industry also seems unlikely to stop replicating the same accessibility errors while doing so… which is not.

As each new-and-shiny UI framework appears, we seem to go through the same stages. At first people insist that it’s too soon to expect accessible solutions, then they insist it’s too late to change things, then finally someone makes a huge effort to fix stuff despite that resistance, then the framework gets dumped for something new and shiny which will be accessible later…

To get off this treadmill, frontenders should start by properly understanding native HTML elements and how they work - even if they never use the pure, native version. You can’t replicate something if you don’t know what it does in the first place.

Where things get a little crazy is just how much native elements are handling for you.

A talk

To illustrate the depth of the challenge, I created a presentation for A11y Camp 2019 where I walked people through the process of really replicating a button with a div.

Three years on, very little has changed other than IE11’s official demise clearing the way to use more modern CSS. The input mode script is, thankfully, no longer required.

A hands-on tutorial

To complement this talk and update the solution for a post-IE11 world, I have now created a hands-on tutorial:

Button vs Div: A test-driven web accessibility tutorial

The tutorial does apply a mild custom style, rather than trying to literally replicate a browser button as I did in the talk. Custom styling is a more realistic scenario, and it opens up a few extra tips on handling different states with a custom design.

No doubt the tutorial still misses something, but it should still be a good primer on how to replicate native functionality.

A starting point for custom elements

Since buttons are just one of many elements you may be called on to customise, the steps in the tutorial can be abstracted into a general guide:

  • Create valid and accessible HTML patterns for all states
  • Handle all input/events that a native element would respond to
  • Filter out all the input/events that a native element would ignore, including when disabled
  • Style all states that the native element would differentiate
  • Avoid styling states that the native element would not differentiate, including when disabled
  • Ensure correct style cues are applied, such as cursors and selection

These steps won’t cover everything, but they will at least get you thinking about more than just assigning some click events.

Getting to know the native elements

Knowing what to replicate does take some experience, but a good starting point is to learn more about the functionality of native elements.

  • Spend some time using the native eqivalent without a mouse. Pay attentention to how you move in and out of the component, how that changes during different states, and how users can make a selection or otherwise trigger an action.
  • Review all the attributes of the native element, and the full range of attribute values. I find MDN’s HTML elements reference handy for this.
  • Look up some ARIA guides for common interactions (eg. Deque University’s ARIA code library).
  • If there is no directly-equivalent element or pattern, look for similar interactions. Is the user triggering an action, making a single selection, making multiple selections, etc. There will be common paradigms.
  • Try using a screen reader, or review Russ Weakley’s HTML test cases which document how common elements are announced in different screen readers.

As before, these steps are not exhaustive; they are designed to lead you into different facets of the problem space.

Further resources

Custom, but better

The goal is not to tell anyone to stop making custom components.

The goal is to make custom components that are cheaper to build, easier to maintain, more usable and more accessible. Using the right HTML element can give you a massive boost towards those goals, as you get so much for free. DIVs do not help with those goals.

So start with good HTML - it remains the foundation of the web.