For each time limit set by content, users must be able to turn off, adjust, or extend the time limit before encountering it.
30s limit, 5s warning
15s limit, 2s warning
60s limit, 10s warning
No active session
Start a session to see timing controls
• Clear warning before expiry
• Multiple extension options
• User has control
• Accessible notifications
• Adjustable time limits
• User-controlled preferences
• Option to disable entirely
• Persistent settings
• Monitors user engagement
• Automatically extends sessions
• Reduces interruptions
• Smart timeout management
• Explains timeout reasons
• Preserves user data
• Quick recovery options
• Helpful error messages
<!-- Good Example: Session with Extension Option -->
<div class="session-manager">
<div class="session-timer" role="timer" aria-live="polite">
<h3>Session Time Remaining</h3>
<div class="time-display">
<span class="time-value" id="timer-display">15:00</span>
<div class="time-bar">
<div class="time-progress" style="width: 75%"></div>
</div>
</div>
</div>
<!-- Session controls -->
<div class="session-controls">
<button onclick="extendSession()" class="extend-btn">
Extend Session (+ 10 minutes)
</button>
<button onclick="disableTimeouts()" class="disable-btn">
Disable Time Limits
</button>
<div class="extensions-remaining">
Extensions remaining: <span id="extensions">2</span>
</div>
</div>
<!-- Warning dialog -->
<div id="timeout-warning" class="warning-dialog" aria-live="assertive" hidden>
<div class="warning-content">
<h3>Session Expiring Soon</h3>
<p>Your session will expire in <span id="warning-time">2</span> minutes.</p>
<div class="warning-actions">
<button onclick="extendSession()" class="primary">
Extend Session
</button>
<button onclick="continueSession()" class="secondary">
Continue Working
</button>
<button onclick="saveAndLogout()" class="secondary">
Save & Logout
</button>
</div>
</div>
</div>
</div>
<!-- Good Example: User Preferences -->
<div class="timing-preferences">
<h3>Timing Preferences</h3>
<form class="preferences-form">
<fieldset>
<legend>Session Length</legend>
<label>
<input type="radio" name="session-length" value="15" checked>
15 minutes (default)
</label>
<label>
<input type="radio" name="session-length" value="30">
30 minutes
</label>
<label>
<input type="radio" name="session-length" value="60">
60 minutes
</label>
<label>
<input type="radio" name="session-length" value="0">
No time limit
</label>
</fieldset>
<fieldset>
<legend>Warning Settings</legend>
<label for="warning-time">Warning time before expiry:</label>
<select id="warning-time" name="warning-time">
<option value="1">1 minute</option>
<option value="2" selected>2 minutes</option>
<option value="5">5 minutes</option>
<option value="10">10 minutes</option>
</select>
</fieldset>
<button type="submit">Save Preferences</button>
</form>
</div>
<!-- Bad Example: No User Control -->
<div class="bad-session">
<div class="fixed-timeout">
<p>Your session will expire in 5 minutes.</p>
<!-- No way to extend or disable -->
</div>
</div>
<script>
// Good implementation with user control
class SessionManager {
constructor(options = {}) {
this.timeLimit = options.timeLimit || 900; // 15 minutes
this.warningTime = options.warningTime || 120; // 2 minutes
this.extensionTime = options.extensionTime || 600; // 10 minutes
this.maxExtensions = options.maxExtensions || 3;
this.allowDisable = options.allowDisable !== false;
this.timeRemaining = this.timeLimit;
this.extensionsUsed = 0;
this.isActive = false;
this.warningShown = false;
this.loadUserPreferences();
this.setupEventListeners();
}
start() {
this.isActive = true;
this.timeRemaining = this.timeLimit;
this.startTimer();
this.updateDisplay();
}
startTimer() {
this.timer = setInterval(() => {
this.timeRemaining--;
this.updateDisplay();
if (this.timeRemaining <= this.warningTime && !this.warningShown) {
this.showWarning();
}
if (this.timeRemaining <= 0) {
this.handleExpiry();
}
}, 1000);
}
extendSession() {
if (this.extensionsUsed >= this.maxExtensions) {
this.showMessage('Maximum extensions reached');
return;
}
this.timeRemaining += this.extensionTime;
this.extensionsUsed++;
this.hideWarning();
this.updateDisplay();
// Announce to screen readers
this.announceToScreenReader(
`Session extended by ${this.extensionTime / 60} minutes. ${this.maxExtensions - this.extensionsUsed} extensions remaining.`
);
}
disableTimeouts() {
if (!this.allowDisable) {
this.showMessage('Timeouts cannot be disabled for this session');
return;
}
clearInterval(this.timer);
this.isActive = false;
this.hideWarning();
this.hideTimer();
this.announceToScreenReader('Session timeouts have been disabled');
}
showWarning() {
this.warningShown = true;
const warningDialog = document.getElementById('timeout-warning');
warningDialog.hidden = false;
warningDialog.focus();
// Announce to screen readers
this.announceToScreenReader(
`Warning: Your session will expire in ${Math.ceil(this.timeRemaining / 60)} minutes`
);
}
announceToScreenReader(message) {
// Create a temporary live region for announcements
const announcement = document.createElement('div');
announcement.setAttribute('aria-live', 'assertive');
announcement.setAttribute('aria-atomic', 'true');
announcement.className = 'sr-only';
announcement.textContent = message;
document.body.appendChild(announcement);
setTimeout(() => document.body.removeChild(announcement), 1000);
}
loadUserPreferences() {
const prefs = localStorage.getItem('sessionPreferences');
if (prefs) {
const parsed = JSON.parse(prefs);
this.timeLimit = parsed.timeLimit || this.timeLimit;
this.warningTime = parsed.warningTime || this.warningTime;
this.extensionTime = parsed.extensionTime || this.extensionTime;
}
}
saveUserPreferences() {
const prefs = {
timeLimit: this.timeLimit,
warningTime: this.warningTime,
extensionTime: this.extensionTime
};
localStorage.setItem('sessionPreferences', JSON.stringify(prefs));
}
}
</script>Remember: Time limits disproportionately affect users with disabilities who may need more time to read, understand, or interact with content.
Always provide user control over timing to ensure equal access to your content and functionality.