Trapping user focus four ways in TypeScript

rossangus

Ross Angus

Posted on November 28, 2023

Trapping user focus four ways in TypeScript

Image by Ksenia Chernaya

Recently, I had to trap the user's focus within an element. This turns out to be a problem with many solutions. The best answer (spoilers!) turns out to be the simplest.

Note that the Codepens below are in TypeScript and should validate to Airbnb linting rules.

Capturing keystrokes

My first pass at this problem was based around capturing the Shift and Tab keystrokes:

Advantages

  • Works if the user presses the keys once, or holds the keys down

Disadvantages

  • Brittle (what if there's a means to move focus which doesn't trigger a keyboard stroke?)
  • Registers three different event listeners (keyup, keydown, focusout)

Remembering the previous element

This updates a variable which represents whatever previously had the focus and works out if the user wants to go forward or backward, based on that.

Advantages

  • The solution is quite elegant (I borrowed it from a StackOverflow post)

Disadvantages

  • It only works correctly if the container has elements which can receive focus both before and after it in the tab order

Using the hidden button method

This uses hidden buttons which flank the content which needs to be contained. When they fall into focus, they push the focus back to the start or end of the element.

Advantages

  • The container can be the first or last element on the page and it still traps the focus

Disadvantages

  • It feels a little dirty to add buttons into the DOM - it might have an impact on accessibility.

Side mission: what happens with a dialog element?

HTML5's dialog element has modal functionality with native focus trapping. What happens to the focus there?

Weird. The focus immediately escapes the current tab and ends up in the chrome of the browser. That reminds me of a motivational poster I once saw:

Motivational-style poster. The image shows a boy running away from the camera on a beach into the sunset. The caption reads The only way to trap focus is to let it escape and return to you when it's ready

Image by Admiral General M. ⭐⭐⭐⭐⭐ GodShepherdly 33277089*

Let's rethink the problem: are we trying to punish the user, or are we trying to direct their attention to one UI element? The functional purpose of a modal is that it stops the user from completing any other task on the current page until it is either completed, or dismissed (refreshing the page is dismissing, right?)

If the user needs to make some adjustment to the browser, then this is a task which absolutely should be possible, before dismissing the modal. None of the previous solutions have taken this into account.

So, taking inspiration from this:

Using tabindex

What if we just set everything which can receive focus to tabindex="-1", apart from elements inside the element we want the user focused on?

Advantages

  • Allows users to adjust the browser using keyboard navigation
  • Relatively simple code
  • No event handlers (apart for the button which turns the focus trap off)

Disadvantages

  • Potentially a whole heap of DOM manipulation (do attributes count as DOM manipulation?)
💖 💪 🙅 🚩
rossangus
Ross Angus

Posted on November 28, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related