Live Region Playground
Live Region Playground
Turn on a screen reader to experience this example in action.
Page Contents:
Configuration Options
Live Region Output:
Static Content
The changing content will take place below.
Reference:
Role | aria-live | aria-atomic | aria-relevant |
---|---|---|---|
Alert | assertive | true | Not dictated by spec (defaults to "text additions"). |
log | polite | Not dictated by spec (defaults to "false"). | Not dictated by spec (logically it should be "additions"). |
marquee | off | Not dictated by spec (defaults to "false"). | Not dictated by spec (defaults to "text additions"). |
status | polite | true | Not dictated by spec (defaults to "text additions"). |
timer | off | Not dictated by spec (defaults to "false"). | Not dictated by spec (defaults to "text additions"). |
HTML Source Code
<div class="liveRegionPlayground">
<div id="loading" tabindex="-1" style="display: none;">Please wait while options are configured...</div>
<fieldset id="live-config">
<legend>How do you want to configure your live region?</legend>
<div class="form">
<div>
<input type="radio" id="default" value="default" name="cus-def" aria-describedby="role-help">
<label for="default">Use role defaults</label>
<span id="role-help" class="helper">(values for aria-live, aria-atomic and aria-relevant will be auto-populated)</span>
</div>
<div>
<input type="radio" id="custom" value="custom" name="cus-def" checked="checked">
<label for="custom">Create custom live region</label>
</div>
</div>
<div class="form">
<label for="role">role:</label>
<select id="role">
<option selected="selected">status</option>
<option>alert</option>
<option>log</option>
<option>marquee</option>
</select>
</div>
<div class="field">
<label for="aria-live">aria-live value:</label>
<select id="aria-live">
<option selected="selected">polite</option>
<option>assertive</option>
<option>off</option>
</select>
</div>
<div class="field">
<label for="aria-atomic">aria-atomic value:</label>
<select id="aria-atomic">
<option selected="selected">true</option>
<option>false</option>
</select>
</div>
<div class="field">
<label for="aria-relevant">aria-relevant value:</label>
<select id="aria-relevant">
<option selected="selected">text</option>
<option>additions</option>
<option>removals</option>
<option>all</option>
</select>
</div>
<div class="field">
<div id="trigger">Trigger content change:</div>
<ul role="list" aria-labelledby="trigger">
<li role="listitem">
<input type="radio" name="trigger-type" aria-describedby="content-change-help" id="once" value="once" checked="checked">
<label for="once">Once</label>
</li>
<li role="listitem">
<input type="radio" name="trigger-type" aria-describedby="content-change-help" id="five" value="five">
<label for="five">Every 5 seconds</label>
</li>
<li role="listitem">
<input type="radio" name="trigger-type" aria-describedby="content-change-help" id="ten" value="ten">
<label for="ten">Every 10 seconds</label>
</li>
</ul>
<div id="content-change-help" class="helper">
Content change will alternate between additions and modifications with the exception of content removal every 10th iteration.
</div>
</div>
<button type="button" id="submit">Submit</button>
<button type="button" id="clear">Clear added content</button>
<button type="button" disabled="disabled" id="stop">Stop adding content</button>
</fieldset>
<h2 id="liveRegionOutput">Live Region Output:</h2>
<div id="fixture">
<div>
<div id="static">
<h3>Static Content</h3>
<div>The changing content will take place below.</div>
</div>
</div>
<div id="update"></div>
</div>
</div>
JavaScript Source Code
Dependencies:
- JQuery
'use strict';
/**
* Live region playground
*
* @author Harris Schneiderman
*/
/* global $*/
var i = 1;
var contentChanges = 1;
var interval;
var $role = $('#role');
var $stop = $('#stop');
var $update = $('#update');
var $fixture = $('#fixture');
var $ariaLive = $('#aria-live');
var $ariaAtomic = $('#aria-atomic');
var $ariaRelevant = $('#aria-relevant');
configureRegion();
// apply attrs based on fields
$('#submit').on('click', configureRegion);
// clear the live region div (except for the "static content")
$('#clear').on('click', function () {
$update.empty();
i = 1;
contentChanges = 1;
});
$('input[name="cus-def"]').on('change', function () {
if ($('#default').is(':checked')) {
$ariaLive.attr('disabled', 'disabled').attr('aria-disabled', 'true');
$ariaAtomic.attr('disabled', 'disabled').attr('aria-disabled', 'true');
$ariaRelevant.attr('disabled', 'disabled').attr('aria-disabled', 'true');
} else {
$ariaLive.removeAttr('disabled').removeAttr('aria-disabled', 'true');
$ariaAtomic.removeAttr('disabled').removeAttr('aria-disabled', 'true');
$ariaRelevant.removeAttr('disabled').removeAttr('aria-disabled', 'true');
}
});
// stop adding content
$stop.on('click', function () {
if (interval) {
clearInterval(interval);
}
});
// configure vals of others based on newly selected role
$role.on('change', onroleChange);
function configureRegion(e) {
if (interval) {
clearInterval(interval);
}
// configure attributes
$fixture
.attr({
'role': $role.val(),
'aria-live': $ariaLive.val(),
'aria-atomic': $ariaAtomic.val(),
'aria-relevant': $ariaRelevant.val()
});
// configure content insertion (if submit was clicked)
if (e) {
configureInsertion();
}
}
function configureInsertion() {
var freq = $('input[name="trigger-type"]:checked').val();
// call `insertContent` based on frequency chosen
if (freq === 'once') {
$stop.attr('disabled', 'disabled');
insertContent();
} else {
$stop.removeAttr('disabled');
freq = (freq === 'five') ? 5 : 10;
interval = setInterval(insertContent, freq * 1000);
}
}
function insertContent() {
if (contentChanges < 10) {
if (isOdd(contentChanges)) {
$update.append('<div><span class="added">Added Content</span> #' + i + '</div>');
if (contentChanges === 9) {
$update.append('<div>Also, more <span class="added">added content</span>! Unfortunately, I will be removed next...</div>');
}
i++;
} else {
$update.find('.added').last().html('Modified Content');
}
} else {
$update.children().last().remove();
contentChanges = 1; // reset it.
}
contentChanges++;
}
function onroleChange() {
if ($('#custom').is(':checked')) {
return;
}
var role = $role.val();
// update <select /> vals based on role
if (role == 'alert') {
$ariaLive.val('assertive');
$ariaAtomic.val('true');
$ariaRelevant.val('text');
} else if (role == 'log') {
$ariaLive.val('polite');
$ariaAtomic.val('false');
$ariaRelevant.val('text');
} else if (role == 'status') {
$ariaLive.val('polite');
$ariaAtomic.val('true');
$ariaRelevant.val('text');
} else if (role == 'marquee') {
$ariaLive.val('off');
$ariaAtomic.val('false');
$ariaRelevant.val('text');
}
// update the attributes right away
configureRegion();
}
function isOdd(n) {
return Math.abs(n) % 2 == 1;
}
CSS Source Code
.liveRegionPlayground label, .liveRegionPlayground #trigger, .liveRegionPlayground #custom-default {
font-size: 1em;
}
.liveRegionPlayground .helper {
font-style: italic;
}
.liveRegionPlayground select {
background-color: #eee;
font-size: 1em;
}
.liveRegionPlayground ul {
margin: 2px;
}
.liveRegionPlayground li {
list-style-type: none;
}
.liveRegionPlayground .inner-field {
font-size: 1em;
margin-left: 20px;
}
.liveRegionPlayground #fixture {
width: 85%;
margin: 0 auto;
text-align: center;
border: 5px solid #000;
height: 300px;
overflow: scroll;
padding: 11px;
}
.liveRegionPlayground #loading {
position: absolute;
width: 500px;
padding: 25px;
text-align: center;
background-color: #000;
color: #fff;
border: 10px double #fff;
}
.liveRegionPlayground #mean {
position: absolute;
clip: rect(1px 1px 1px 1px);
clip: rect(1px, 1px, 1px, 1px);
overflow: hidden;
width: 1px;
height: 1px;
}