Time Adjustment
Various user groups such as users with visual, motor and cognitive impairments may require more time to complete a task that has a time limit on it. This can make it difficult for them to use the website.
However, there are some exceptions where time constraints are required. They are:
- Real-time events such as online exams, auctions etc.
- Booking tickets
- The time limit is more than 20 hours.
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.
- The best way is to avoid providing time-based tasks unless it is required.
-
If time-based tasks are unavoidable,
- Ensure that proper instructions informing the users that the activity is timed, and the time given to finish the activity SHOULD be included on the page.
-
If the time limit is provided, make sure that ANY ONE of the following is followed:
- Providing users with an option to turn off the time limit before starting.
- Providing users with an option to adjust the time limit before starting over the range of 10 times higher than the given time.
- If the activity is a multistep one, then it SHOULD allow users to set the time as per their need and then carry across this limit across all steps.
- Providing users with an option to extend the time limit at least 20 seconds before the session expires. This CAN be implemented using a simple click of a button such as “Extend session” in the example and MUST be available at least 10 times. However, when users have extended the time by multiple times say 7 or 8, and it is about to exhaust, then they SHOULD be informed that they have only 3 or 2 tries available for extending time limit.
- The buttons given to turn off or adjust the time limit SHOULD be accessible for all users.
- Descriptive labels SHOULD be provided for the buttons.
- The contrast requirement of 3:1 ratio MUST be met with the adjacent colors for the large button text in default, focus and hover states.
- The contrast requirement of 3:1 ratio MUST be met with the adjacent colors for the custom focus indicator of the buttons.
- The contrast requirement of 4.5:1 ratio MUST be met with the adjacent colors for the button text in default, focus and hover states.
A well-defined time adjustment benefits majorly the below users.
- People with cognitive disabilities
- People with visual disabilities
- People using speech input
- People with limited dexterity
- People using keyboard only
The HTML for all 5 pages is included here.
<div class="container" id="container">
<p id="logout_msg">
Your session will expire if you stay inactive for longer period
</p>
<form id="contact-us" onsubmit="return checkError(this)" method="post">
<p>
<strong>Fields marked with asterisk (<span class="span">*</span>)
are mandatory.</strong>
</p>
<div class="form-control">
<label for="firstname">First Name:<span class="span">*</span></label>
<input type="text" name="firstname" id="firstname" autocomplete="given-name" aria-required="true">
</div>
<div class="form-control">
<label for="lastname">Last Name:<span class="span">*</span></label>
<input type="text" name="lastname" id="lastname" autocomplete="family-name" aria-required="true">
</div>
<div class="form-control">
<label for="email">Email:<span class="span">*</span></label>
<input type="email" id="email" autocomplete="email" name="email" aria-required="true">
</div>
<div class="form-control">
<label for="phone">Phone:<span class="span">*</span></label>
<input type="tel" name="phone" autocomplete="tel" id="phone" aria-required="true" maxlength="14">
</div>
<input name="submit" id="submit" type="submit" value="Submit">
</form>
</div>
<div id="popup" class="popup" role="alertdialog" aria-labelledby="popup-title" aria-describedby="timerMessage">
<div class="popup-content">
<h2 id="popup-title">Session Timeout Warning</h2>
<p id="timerMessage" aria-live="polite">
Your session is about to expire due to inactivity. This session will
log out in <span id="countdown">20</span> seconds.
</p>
<button id="extendSession">Extend Session</button>
<button id="cancelSession">Logout</button>
</div>
</div>
<div id="ariaLiveRegion" aria-live="polite"></div>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Inter", sans-serif;
}
:root {
--light-grey: #eeeeee;
--border: 1px solid var(--light-grey);
}
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
h1 { margin-bottom: 1.5rem; }
ul {
list-style: none;
}
a {
text-decoration: none;
color: inherit;
}
button {
border: none;
background-color: transparent;
cursor: pointer;
color: inherit;
}
.icon {
padding: 0.5rem;
background-color: var(--light-grey);
border-radius: 10px;
}
.logo {
margin-right: 1.5rem;
}
#nav-menu {
border-bottom: var(--border);
}
.nav-container {
display: flex;
align-items: center;
justify-content: space-between;
column-gap: 2rem;
height: 90px;
padding: 1.2rem 3rem;
background-color: #005a70;
}
.menu {
position: relative;
background: #005a70;
color: #fff;
}
.menu-bar li:first-child .dropdown {
flex-direction: initial;
min-width: 480px;
}
.menu-bar li:first-child ul:nth-child(1) {
border-right: var(--border);
}
.menu-bar li:nth-child(n + 2) ul:nth-child(1) {
border-bottom: var(--border);
}
.menu-bar .dropdown-link-title {
font-weight: 600;
}
.menu-bar .nav-link {
font-size: 1rem;
font-weight: 500;
letter-spacing: -0.6px;
padding: 0.3rem;
min-width: 60px;
margin: 0 0.6rem;
}
.menu-bar .nav-link:hover,
.dropdown-link:hover {
text-decoration: underline;
}
.nav-start,
.nav-end,
.menu-bar,
.right-container,
.right-container .search {
display: flex;
align-items: center;
z-index: 1000;
}
#hamburger {
display: none;
padding: 0.1rem;
margin-left: 1rem;
font-size: 1.9rem;
}
@media (max-width: 1100px) {
#hamburger {
display: block;
color: #fff;
}
.nav-container {
padding: 1.2rem;
}
.menu {
display: none;
position: absolute;
top: 87px;
left: 0;
min-height: 100vh;
width: 100vw;
}
.menu-bar li:first-child ul:nth-child(1) {
border-right: none;
border-bottom: var(--border);
}
.dropdown {
display: none;
min-width: 100%;
border: none !important;
border-radius: 5px;
position: static;
top: 0;
left: 0;
visibility: visible;
opacity: 1;
transform: none;
box-shadow: none;
}
.menu.show,
.dropdown.active {
display: block;
}
.dropdown ul {
padding-left: 0.3rem;
}
.menu-bar {
display: flex;
flex-direction: column;
align-items: stretch;
row-gap: 1rem;
padding: 1rem;
}
.menu-bar .nav-link {
display: flex;
justify-content: space-between;
width: 100%;
font-weight: 600;
font-size: 1.2rem;
margin: 0;
}
.menu-bar li:first-child .dropdown {
min-width: 100%;
}
.menu-bar > li:not(:last-child) {
padding-bottom: 0.5rem;
border-bottom: var(--border);
}
}
.cards {
flex: 0 1 60%;
margin-right: 20px;
}
.cards h2 {
font-size: 1.5rem;
margin-bottom: 10px;
color:rgb(0, 102, 204);
}
.cards p {
font-size: 1rem;
line-height: 1.5;
}
#main {
margin: 20px;
padding: 20px;
}
.card-container {
display: flex;
flex-direction: row;
justify-content: center;
flex-wrap: wrap;
list-style: none;
margin: 0;
padding: 0;
}
.cards > * {
flex: 0 1 20em;
}
.card {
margin: .75em;
padding: .75em;
border-radius: 3px;
border: 2px #ccc solid;
border-radius: .6em;
background-color: white;
position: relative;
}
img {
width: 100%;
height: auto;
}
.reorder {
display: flex;
flex-direction: column;
}
.reorder img {
max-width: 100%;
order: -1;
}
.cards > * a {
display: block;
color: rgb(0, 102, 204);
}
.cards h2 > a {
text-decoration: none;
}
article:hover {
box-shadow: 0 0 0 0 0.25rem;
}
.footer {
position: relative;
bottom: 0;
width: 100%;
text-align: center;
padding: 20px 0;
margin: 0;
background-color: #007fa3;
color: #fff;
}
.footer ul li {
list-style: none;
display: inline-block;
padding: 0;
margin: 10px;
}
.footer ul li a {
font-size: 1.2rem;
color: #fff;
}
.footer ul li a:hover {
text-decoration: underline;
}
.aside {
background-color: #f2f2f2;
padding: 20px;
margin: 20px;
flex: 0 1 30%;
margin-left: 20px;
height: fit-content;
}
.container {
display: block;
}
@media (max-width: 768px) {
.cards { flex: 0 1 90%; }
}
.fld-press-release-report-item {
padding-top: 43px;
padding-left: 48px;
padding-bottom: 23px;
float: left;
}
.press-release-content-box {
display: block;
float: left;
max-width: 100%;;
}
.section-heading-content-title h2 {
font-size: 1.5rem;
font-weight: 700;
font-stretch: normal;
font-style: normal;
line-height: 1.42;
letter-spacing: 0.5px;
color: #000;
margin-right: 35px;
}
.section-heading-link-download {
padding-top: 20px;
padding-bottom: 20px;
border-top: 4px solid #ae367e;
z-index: 10;
}
.section-heading-link-download a {
position: relative;
display: inline-block;
font-size: 1rem;
font-weight: 700;
font-stretch: normal;
font-style: normal;
line-height: 1.5;
letter-spacing: 1px;
color: #000;
width: 100%;
}
.press-release-image-box {
display: block;
float: left;
}
.press-release-content-image {
position: relative;
height: 275px;
width: 212px;
}
.press-release-content-image img {
position: relative;
z-index: 1;
width: 100%;
height: 100%;
}
.press-release-content-image:after {
position: absolute;
content: "";
width: 212px;
height: 275px;
background: #fff;
border-radius: 2px;
z-index: 0;
left: 22px;
margin-top: 22px;
}
span {
font-size: 24px;
color: #fff;
}
.req { color: #db0020; }
.popup {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
align-items: center;
justify-content: center;
}
.popup-content {
background-color: white;
padding: 20px;
border-radius: 5px;
text-align: center;
}
.popup-content button {
color: #ffffff;
background-color: #005A70;
}
button {
font-size: 1rem;
padding: 0.5rem 1rem;
margin: 0.5rem;
border: none;
border-radius: 5px;
cursor: pointer;
background-color: #007bff;
color: white;
}
button:hover { background-color: #0056b3; }
input,
textarea {
display: block;
margin-bottom: 0.2rem;
padding: 0.8rem;
border: 1px solid #8e8e8e;
line-height: 1.15;
width: 40%;
border-radius: 4px;
}
input[type=submit] {
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 {
background-color: #068379;
cursor: pointer;
text-decoration: none;
}
#ariaLiveRegion{
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px);
clip: rect(1px, 1px, 1px, 1px);
font-size: 14px;
white-space: nowrap;
}
#countdown {
color: black;
}
let popup = document.getElementById('popup');
let extendButton = document.getElementById('extendSession');
let cancelButton = document.getElementById('cancelSession');
let countdownElement = document.getElementById('countdown');
let countdown = 20;
let countdownInterval;
let sessionTimeout = 5000;
let extended = false;
let sessionTimeoutID;
let loggedOut = false;
function startCountdown() {
countdownInterval = setInterval(() => {
countdown--;
countdownElement.textContent = countdown;
if (countdown <= 0) {
clearInterval(countdownInterval);
if (!extended) {
logoutUser();
}
}
}, 1000);
}
function handleSessionTimeout() {
if (!extended && !loggedOut) {
showPopup();
}
}
function logoutUser() {
hidePopup();
if (!loggedOut) {
loggedOut = true;
document.getElementById('container').style.display = 'none';
document.getElementById('logout_msg').style.display = 'none';
let logoutMessage = document.createElement('p');
logoutMessage.textContent = 'Your session has timed out. You are now logged out.';
document.body.appendChild(logoutMessage);
}
}
extendButton.addEventListener('click', () => {
hidePopup();
clearInterval(countdownInterval);
extended = true;
countdown = 20;
sessionTimeout = 30000;
resetCountdown();
resetSessionTimeout();
updateAriaLiveRegion('Session extended. your session is extended for 50 second.');
});
cancelButton.addEventListener('click', () => {
clearInterval(countdownInterval);
clearTimeout(sessionTimeoutID);
logoutUser();
updateAriaLiveRegion('You have been logged out due to inactivity.');
});
function updateAriaLiveRegion(message) {
let ariaLiveRegion = document.getElementById('ariaLiveRegion');
ariaLiveRegion.textContent = message;
setTimeout(() => {
ariaLiveRegion.textContent = '';
}, 5000);
}
function hidePopup() {
popup.style.display = 'none';
}
function showPopup() {
popup.style.display = 'flex';
resetCountdown();
startCountdown();
extendButton.focus();
}
function resetCountdown() {
clearInterval(countdownInterval);
countdown = 20;
countdownElement.textContent = countdown;
}
function resetSessionTimeout() {
clearTimeout(sessionTimeoutID);
sessionTimeoutID = setTimeout(showPopup, sessionTimeout);
}
document.addEventListener('mousemove', () => {
if (!extended && !loggedOut) {
resetSessionTimeout();
}
});
document.addEventListener('keydown', () => {
if (!extended && !loggedOut) {
resetSessionTimeout();
}
});
sessionTimeoutID = setTimeout(showPopup, sessionTimeout);
Due to the nature of this demonstration, it is best
viewed full screen
.