Keyboard Trap
Keyboard-only users navigate a website using only a keyboard. When their focus gets trapped on an element, a keyboard trap occurs. Due to this, they are unable to navigate forward/backward on the page.
Another example of keyboard trap is when a modal dialog appears on a page and the user is unable to dismiss it using keyboard. One way of ensuring that keyboard trap does not occur is to manage scripts.
NOTE:
- New to accessibility or uncertain of requirements, it will be helpful to review all sections below.
- Already familiar with requirements, skip to the “Working Example” section for sample HTML, CSS and JavaScript (when needed), along with a working demo.
- There SHOULD NOT be any keyboard trap on the elements while navigating through with the keyboard.
- Keyboard trap CAN be implemented in case of essential components where a trap is required. For example, modal dialogs where the focus SHOULD stay within the dialog unless it is closed via an Esc key or Close button. For more information on Modal Dialog, refer to Modal Dialog component.
- Ensure scripts are implemented correctly such that there are no Keyboard Traps on any elements unless required for the functionality of the component.
Keyboard trap majorly affects the below users.
- People with cognitive disabilities
- People with visual disabilities
- People using speech input
- People using keyboard only
<h2>Join millions of people learning 41 languages</h2>
<p>
Whether for fun or traveling abroad, you can get fluent easier, faster, and
smarter. Enjoy bite-sized lessons designed by world-class linguists based on
real-world situations, – so you'll only learn what's relevant.
</p>
<h3>Select an eTextbook and start your Pearson+ subscription today.</h3>
<button id="openModalButton">Start Learning</button>
<div id="modal" class="modal" aria-modal="true" aria-labelledby="modalTitle" role="dialog">
<div class="modal-content">
<button id="closeModalButton" class="close-button" aria-label="Close Modal">X</button>
<h2 id="modalTitle">Login</h2>
<form id="contact-us" method="post">
<p>
<strong>Fields marked with asterisk
(<span class="span">*</span>) are mandatory.</strong>
</p>
<div class="form-control">
<label for="firstname">Full Name:<span class="span">*</span></label>
<input type="text" name="firstname" id="firstname" autocomplete="name" required>
</div>
<div class="form-control">
<label for="password">Password:<span class="span">*</span></label>
<input type="password" id="password" autocomplete="current-password" name="password" required>
</div>
<input name="submit" id="submit" type="submit" value="Submit">
</form>
</div>
</div>
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 1;
}
.modal-content {
background: #fff;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 20px;
border: 1px solid #ccc;
}
.close-button {
position: absolute;
top: 10px;
right: 10px;
cursor: pointer;
font-size: 18px;
}
input {
display: block;
margin-bottom: 0.2rem;
padding: 0.8rem;
border: 1px solid #8e8e8e;
line-height: 1.15;
width: 90%;
border-radius: 4px;
}
input[type=submit], #openModalButton {
background-color: #003057;
border: 2px solid #000;
border-radius: 10px;
color: #fff;
display: inline-block;
line-height: 1.15;
padding: 0.35rem 1rem;
width: auto;
text-align: center;
text-decoration: none;
margin: 0 2rem 0 0;
font-size: 1rem;
vertical-align: middle;
}
input[type=submit]:hover,
input[type=submit]:focus,
#openModalButton:hover,
#openModalButton:focus {
background-color: #068379;
cursor: pointer;
text-decoration: none;
}
@media only screen and (max-width: 600px) {
.modal-content { width: 80%; }
}
const openModalButton = document.getElementById('openModalButton');
const closeModalButton = document.getElementById('closeModalButton');
const modal = document.getElementById('modal');
const username = document.getElementById('firstname');
const password = document.getElementById('password');
const submit = document.getElementById('submit');
const focusableElements = [username, password, submit, closeModalButton];
let previouslyFocusedElement;
function openModal() {
previouslyFocusedElement = document.activeElement;
modal.style.display = 'block';
if (focusableElements.length > 0) {
focusableElements[0].focus();
}
}
function closeModal() {
modal.style.display = 'none';
previouslyFocusedElement.focus();
}
openModalButton.addEventListener('click', openModal);
closeModalButton.addEventListener('click', closeModal);
closeModalButton.addEventListener('keydown', function (e) {
if (e.key === 'Tab' && e.shiftKey) {
e.preventDefault();
submit.focus();
}
});
submit.addEventListener('keydown', function (e) {
if (e.key === 'Tab' && !e.shiftKey) {
e.preventDefault();
closeModalButton.focus();
}
});
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape' && modal.style.display === 'block') {
modal.style.display = 'none';
openModalButton.focus();
}
});
submit.addEventListener('click', validateForm);
function validateForm() {
const firstname = document.getElementById('firstname').value;
const password = document.getElementById('password').value;
let errorMessage = '';
let focusField = null;
if (!firstname) {
errorMessage += 'Please fill out the Full Name field.\n';
if (!focusField) {
focusField = document.getElementById('firstname');
}
}
if (!password) {
errorMessage += 'Please fill out the Password field.\n';
if (!focusField) {
focusField = document.getElementById('password');
}
}
if (errorMessage) {
alert(errorMessage);
if (focusField) {
focusField.focus();
}
return false;
}
alert('Login successfully!');
window.location.href = 'https://accessibility.pearson.com/';
return false;
}
Due to the nature of this demonstration, it is best
viewed full screen
.