A focus trap is a very important accessibility feature within a web application. In this post, I’ll first help you understand what it is, then why it’s important, and finally, I’ll show how to quickly and easily add the concept within your Angular apps where needed. And, it’s pretty easy thanks to the Angular CDK. Alright, let’s get to it.
Accessibility can be a little difficult to understand or even think about if you’re someone who can see, hear, and use the web easily with different devices, so it can also be easy to build things that don’t work well for those who can’t.
What Is a Focus Trap?
A focus trap is a feature that helps make experiences better for these folks. It’s a way of managing user focus within a given container.
Take, for example, a modal. If a user opens a modal without managing focus, when they start navigating via the keyboard by using the tab key, items behind the modal continue to receive focus. This is weird and not what the user would expect, right? We need to programmatically focus them within the modal.
But this isn’t enough; if we stop here, as we tab through the modal, eventually, we’ll tab through all of the focusable items, and then, we’ll be back to focusing items within the original document behind the modal again.
What we need to do instead is trap the focus so that when the user focuses on the last item in the modal, the focus will be placed back on the first focusable element in the modal on the next tab.
Ok, now that we know what a focus trap is, we are probably beginning to realize that there’s going to be some effort to create this functionality, right?
Well, not within Angular. With the CDK, this is pretty easy using the cdkTrapFocus
directive from the A11yModule
.
The Angular cdkTrapFocus
Directive
Let’s look at an example. Here, we have a web app for the Vans shoe brand.
Up at the top, we have a sign-up button. When we click it, and then tab around, we can see focus is moving around the items in the background.
Not what we want, right?
Ok, let’s add the cdkTrapFocus
. First thing we need to do in order to use it is, we need to import the A11yModule
.
sign-up-modal.component.ts
import { A11yModule } from '@angular/cdk/a11y';
@Component({
selector: 'app-sign-up-modal',
...
imports: [A11yModule]
})
export class SignUpModalComponent {
}
For those of you who are unfamiliar with this acronym, Ally is an abbreviation for the word accessibility. It comes from the concept that the word begins with an A, ends with a Y, and there are eleven characters in between.
The Angular CDK has several accessibility features within its accessibility module, and the cdkTrapFocus
directive is one of them.
So, once we have it imported, we can now use it within the template. We just need to add it to an element that wraps our form.
sign-up-modal.component.html
<div cdkTrapFocus>
<app-sign-up-form (formSubmitted)="modalClose.emit()"></app-sign-up-form>
...
</div>
Providing a Focus on Initialization With the cdkTrapFocusAutoCapture
@Input
Good news, the cdkTrapFocus
directive has an auto-focus feature built right in. We can use the cdkTrapFocusAutoCapture
@Input
. This input will automatically focus the first focusable item within the directive when it’s initialized. It defaults to false, so we need to provide a value of true.
<div cdkTrapFocus [cdkTrapFocusAutoCapture]="true">
<app-sign-up-form (formSubmitted)="modalClose.emit()"></app-sign-up-form>
...
</div>
Now, when we open the modal, the name field is properly focused when it’s opened. And, as we tab through, when we get to the close button, we’ll cycle back to the name field. Also, if we hit shift
+ tab
to navigate backward, we’ll go in reverse order all without leaving the modal.
So, not only is it super helpful for all users really, but it’s super easy to implement too.
One last thing to note, the trap focus directive keeps track of the last focused element before its initialization, so when we close the modal, the focus is returned to the button that opened it.
Nice, we just saved a ton of work and made our modal more accessible.
Want to See It in Action?
Check out the demo code and examples of these techniques in the stackblitz example below. If you have any questions or thoughts, don’t hesitate to leave a comment.