In this tutorial, we will guide you through the process of building accessible popups using the power of jQuery. We will focus on implementing keyboard accessibility, managing focus, leveraging ARIA attributes, and following best practices to ensure that your popups are usable and inclusive.
So, let’s dive in and learn how to create accessible popups that enhance user experience and make your website more inclusive!”
Setting Up the HTML Structure
To start building our accessible popup, we need to set up the HTML structure. We’ll define the markup for the popup container and add trigger elements that will open the popup when interacted with.
<html lang="en"> <head> <meta charset="UTF-8"> <title>Poppu tutorial</title> <link rel="stylesheet" href="style.css"> <!-- jquery --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> </head> <body> <div class="container"> <!-- Trigger button for the modal --> <button id="modalTrigger" aria-haspopup="dialog" aria-expanded="false">Open Modal</button> <!-- Modal container --> <div id="modalContainer" role="dialog" aria-modal="true" aria-labelledby="modalTitle" aria-describedby="modalDescription"> <!-- Modal content --> <div id="modalContent"> <h2 id="modalTitle">This is My Modal Title</h2> <p id="modalDescription"> This is my modal description. It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. </p> <!-- Add your modal content here --> <button id="modalClose" aria-label="Close Modal">Close</button> </div> </div> </div> <script src="custom.js"></script> </body>
Attributes used and their purpose:
aria-haspopup="dialog"
: This attribute is applied to the trigger button (modalTrigger
). It indicates that activating the button will display a dialog or a modal popup.aria-expanded="false"
: This attribute is also applied to the trigger button (modalTrigger
). It indicates the current state of the modal, where “false” means that the modal is initially hidden or collapsed.role="dialog"
: This attribute is applied to the modal container (modalContainer
). It specifies the role of the element as a dialog or a modal window.aria-modal="true"
: This attribute is also applied to the modal container (modalContainer
). It indicates that the modal is a top-level window and should be treated as a modal dialog by assistive technologies.aria-labelledby="modalTitle"
: This attribute is applied to the modal container (modalContainer
). It references the element with the ID “modalTitle” (<h2 id="modalTitle">
) to provide an accessible name or label for the modal.aria-describedby="modalDescription"
: This attribute is also applied to the modal container (modalContainer
). It references the element with the ID “modalDescription” (<p id="modalDescription">
) to provide a description or additional information about the modal.aria-label="Close Modal"
: This attribute is applied to the close button (modalClose
). It provides an accessible name or label for the button, specifying that it is used to close the modal.
These ARIA attributes help improve the accessibility of the modal by providing additional information and context for assistive technologies, such as screen readers, to understand the purpose and behavior of the modal. They ensure that users with disabilities can navigate and interact with the modal effectively.
It’s important to use ARIA attributes appropriately and according to their intended purpose to ensure the accessibility of your web content.
Popup Functionality using jQuery
$(document).ready(function () { var modalTrigger = $("#modalTrigger"); var modal = $("#modalContainer"); var firstFocusableElement; var lastFocusableElement; function showPopup() { modal.addClass("show"); // Add class to show the modal modal.attr("aria-hidden", "false"); // Set aria-hidden to false // Find the first and last focusable elements inside the modal var focusableElements = modal.find( 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])' ); firstFocusableElement = focusableElements.first(); lastFocusableElement = focusableElements.last(); modal.on("keydown", trapFocus); // Shift keyboard focus to modal content var modalContent = $("#modalContent"); modalContent.attr("tabindex", "0"); modalContent.focus(); } function closeModal() { modal.removeClass("show"); // Remove class to hide the modal modal.attr("aria-hidden", "true"); // Set aria-hidden to true modal.off("keydown", trapFocus); // Remove event listener for focus trapping modalTrigger.focus(); // Set focus back to the trigger button // Show ARIA alert for screen readers that the modal is closed var modalClosedAlert = $("<div>") .text("Modal closed") .addClass("sr-only") .attr("role", "alert"); modal.append(modalClosedAlert); setTimeout(function () { modalClosedAlert.remove(); }, 1000); } function trapFocus(event) { if (event.keyCode === 9) { // Trap focus within the modal on "Tab" key press if (event.shiftKey) { if ($(document.activeElement).is(firstFocusableElement)) { event.preventDefault(); lastFocusableElement.focus(); } } else { if ($(document.activeElement).is(lastFocusableElement)) { event.preventDefault(); firstFocusableElement.focus(); } } } if (event.keyCode === 27) { // Close modal on "Escape" key press closeModal(); } } modalTrigger.on("click", showPopup); $("#modalClose").on("click", closeModal); });
The code provided sets up an accessible popup using jQuery. Here’s a description of how the code works:
- The code is wrapped within a
$(document).ready()
function to ensure that the code executes after the document has finished loading. - The variables
modalTrigger
andmodal
are assigned jQuery objects representing the trigger button and the modal container, respectively. - The
showPopup()
function is defined to handle the opening of the modal. When the function is called, it adds the “show” class to the modal container and sets thearia-hidden
attribute to “false” to indicate that the modal is visible. - Inside the
showPopup()
function, the first and last focusable elements within the modal are identified using thefocusableElements
selector. The first element is stored in thefirstFocusableElement
variable, and the last element is stored in thelastFocusableElement
variable. - The
keydown
event listener is attached to the modal using themodal.on("keydown", trapFocus)
syntax. This event listener calls thetrapFocus()
function, which manages the keyboard focus trapping within the modal. - The
trapFocus()
function checks for key events. If the “Tab” key is pressed, it traps the focus within the modal by checking the current active element and shifting the focus to the first or last focusable element accordingly. If the “Escape” key is pressed, it calls thecloseModal()
function to close the modal. - The
closeModal()
function is defined to handle the closing of the modal. It removes the “show” class from the modal container, sets thearia-hidden
attribute to “true”, removes thekeydown
event listener, and sets the focus back to the modal trigger button. It also appends a visually hidden ARIA alert to announce the closure of the modal to screen readers. - The
modalTrigger
is assigned a “click” event listener that triggers theshowPopup()
function when clicked. Similarly, the “click” event listener is attached to the element with the ID “modalClose” to call thecloseModal()
function when clicked.
Style the popup
Finally some basic styling of our popup.
/* Styles for the modal container */ #modalContainer { /* Set modal properties */ position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.5); /* Semi-transparent background */ display: none; /* Hide initially */ } #modalContainer.show { display: block; /* Show when the #modalContainer.show class is added */ } /* Styles for the modal content */ #modalContent { /* Set modal properties */ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: #ffffff; padding: 20px; } /* Styles for the close button */ #modalClose { /* Set close button properties */ position: absolute; top: 10px; right: 10px; } .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0; }