kvack.dev

Make that DIV behave like a button

Published on

While using a native button element is the best way to ensure full accessibility, there might be cases where we need to create custom buttons using other elements. But, adding a click event handler to a div is not enough to make it accessible or even behave like a native button. Let's see what we can do about that.

  1. Add a role="button" attribute to the element. This automatically adds it to the accessibility tree, allowing it to be recognized as a button by assistive technology.

  2. Enable keyboard navigation with tabindex="0", unless the element is already focusable by default. Remember to keep the tabindex value at 0 to maintain an intuitive tab flow.

  3. Enable keyboard events. When the element has focus, users should be able to trigger a "click" by using the Enter and Space bar keys.

    For the Enter key, the action should trigger on key down. For the Space bar, the action should trigger on key up.

    Also, consider preventing the default behavior. For instance, the Space bar key might trigger a page scroll if not handled.

When implemented, the HTML element should look like this:

<div role="button" tabindex="0" onclick="handleClick()">Button</div>

And the event handlers should look something like this:

document.addEventListener('keydown', (event) => {
  const { activeElement } = document
  const hasButtonRole = activeElement?.getAttribute('role') === 'button'

  if (hasButtonRole) {
    // prevent default behaviour, including scrolling on spacebar
    if (['Spacebar', ' ', 'Enter'].includes(event.key)) {
      event.preventDefault()
    }

    if (event.key === 'Enter') {
      activeElement.click()
    }
  }
})

document.addEventListener('keyup', (event) => {
  const { activeElement } = document
  const hasButtonRole = activeElement?.getAttribute('role') === 'button'

  if (hasButtonRole && ['Spacebar', ' '].includes(event.key)) {
    event.preventDefault()
    activeElement.click()
  }
})

Now we have an element with the same functionality as a native button, while also making the web a little more accessible.

Happy coding!