Author: Kevin Babbitt, Melanie Richards
Last updated: 2021-01-07
This document is intended as a starting point for engaging the community and standards bodies in developing collaborative solutions fit for standardization. As the solutions to problems described in this document progress along the standards-track, we will retain this document as an archive and use this section to keep the community up-to-date with the most current standards venue and content location of future work and discussions.
Virtualized content allows an author to efficiently represent a large body of information at once. In this practice, only a fraction of the information is actually present in the markup - typically the portion that is currently visible, plus a small amount preceding or following in order to allow for scrolling. As the user scrolls the web page, JavaScript code will load more content and insert it into the markup at the appropriate location. This process is referred to as realizing the content.
Virtualized content presents challenges for users of assistive technologies (ATs). Generally, an AT's view of the document is limited to what is physically present in the markup. Without some indication that further content exists, the AT cannot accurately describe and navigate the web page. For example, some ATs allow the user to skim the headings in a document by jumping from one to the next. After reading the last realized heading, the AT has no way of knowing that another heading might exist in virtualized content, nor does it have a way of discovering that there is even virtualized content to begin with. The AT, and the user, thus incorrectly conclude that the last heading in the document has been reached.
A new attribute, aria-virtualcontent, indicates whether an element contains virtualized content. The default value is none.
A virtual content container is any element that has a non-default value for aria-virtualcontent.
A virtual content edge is an edge of a virtual content container where the webpage can realize content.
The aria-virtualcontent attribute can have one of several keyword values, or multiple values separated by spaces, establishing which edges of the container are virtual content edges: block-end, block-start, inline-end, inline-start.
For potential future expansions of this API, such as hint(s) about the nature of the virtualized content, please refer to Potential additions to proposed API.
Marking an element as a virtual content container establishes a contract between the web page and ATs. Specifically:
The following simplified example shows one potential usage pattern for aria-virtualcontent.
<html>
<head>
<script src="virtualcontent.js"></script>
</head>
<body>
<main id="main" aria-virtualcontent="block-end" aria-busy="false">
<h1>Section 1</h1>
...
<h1>Section 2</h1>
<h2>Section 2.1</h2>
...
<!-- etc... --->
<div id="loading_spinner" role="presentation" style="visibility:hidden">
<img src="loading.gif" role="presentation">
</div>
</main>
<div id="announcer" aria-live="assertive" style="width: 0; height: 0; overflow: hidden"></div>
</body>
</html>
virtualcontent.js:
// Issues a request to the server for the next section of content.
function begin_load_next_section() {
// Issue request to server.
// ...
}
// Callback triggered when the server responds with next section of content.
function end_load_next_section(response) {
// Signal to the AT that we're loading more content.
document.getElementById("main").setAttribute("aria-busy", "true");
// Insert response payload into the DOM.
document.getElementById("main").appendChild(...);
// Signal to the AT that we're done loading.
document.getElementById("main").setAttribute("aria-busy", "false");
// Signal to the user that we're done loading.
document.getElementById("loading_spinner").style.visibility = "hidden";
document.getElementById("announcer").textContent = "Next section loaded.";
// Update the state of the virtual content container.
if (response.isAtEndOfDocument) {
document.getElementById("main").removeAttribute("aria-virtualcontent");
}
}
// Listens for scroll events and responds accordingly.
function on_scroll_changed() {
// Check whether the user has scrolled to the bottom of the page.
let target = document.documentElement;
let top = (target && target.scrollTop) || document.body.scrollTop;
if (top + target.clientHeight >= target.scrollHeight) {
// Issue request to the server.
begin_load_next_section();
// Signal to the user that we're loading more content.
document.getElementById("loading_spinner").style.visibility = "visible";
document.getElementById("announcer").textContent = "Loading additional content.";
}
}
// Initialize scroll handler.
window.addEventListener("scroll", on_scroll_changed);
main element is partially visible in the viewport. This element's bottom edge is below the bottom edge of the viewport. Because it has aria-virtualcontent set, it is a virtual content container.main element and sees that it is a virtual content container.on_scroll_changed() function is called in reaction to the scroll event. Script code issues a request to a backing server for additional content, displays a loading spinner, and announces that additional content is being loaded using an ARIA live region.end_load_next_section() function is called. Script code inserts the new content into the DOM at the bottom of the virtual content container, hides the loading spinner, and announces to the user that additional content is available.aria-virtualcontent attribute from the main element to indicate there is no more virtualized content.This example illustrates one use of aria-virtualcontent for virtualized content in the inline direction. The document in this scenario is a table of bug reports with the following columns: report ID, report date, status, assigned to, title, fix date, fixed by.
In a fully-realized table, a typical AT would walk the table in row-major order, stopping and reading out each cell in turn. In this example, the content author has incorporated script that keeps only a subset of columns realized depending on viewport width, and the viewport width is such that the script will keep no more than five columns realized at a time. The AT achieves the same reading order as for a fully-realized table by checking for virtualized content in the inline direction whenever it's ready to advance from the last realized cell in a row.
<html>
<body>
<table aria-virtualcontent="block-end inline-end" aria-colcount="7" aria-busy="false">
<thead>
<tr>
<th>ID</th>
<th>Status</th>
<th>Assigned To</th>
<th>Report Date</th>
<th>Title</th>
<!-- <th>Fix Date</th> - Virtualized -->
<!-- <th>Fixed By</th> - Virtualized -->
</tr>
</thead>
<tbody>
<tr>
<td>338</td>
<td>Closed</td>
<td>Alice</td>
<td>April 21</td>
<td>Widget freezes up when the network is slow</td>
<!-- <td>Fix Date</td> - Virtualized -->
<!-- <td>Fixed By</td> - Virtualized -->
</tr>
<tr>
<td>342</td>
<td>Fixed</td>
<td>Bob</td>
<td>April 22</td>
<td>Crash when shift-double-clicking the widget</td>
<!-- <td>Fix Date</td> - Virtualized -->
<!-- <td>Fixed By</td> - Virtualized -->
</tr>
</tbody>
</table>
</body>
</html>
Backing script performing similar functions as Example 1's virtualcontent.js is assumed to be present.
An AT navigating the above content by table cells might result in the following flow:
aria-virtualcontent attribute, script replaces the inline-end token with inline-start.aria-virtualcontent attribute, script replaces the inline-start token with inline-end.aria-virtualcontent attribute, the same as in step 3.aria-virtualcontent attribute, the same as in step 6.The proposed API aims for flexibility in assistive technologies’ user experiences. If deemed useful by the community, the API could potentially be extended to provide more precise hints.
The aria-virtualcontent attribute or a related attribute (e.g. aria-virtualcontenttypes)
could provide a hint to assistive technologies as to important types of content that are currently virtualized.
Such a hint could take space-separated keywords as its value (e.g. headings, tables),
and a default, implicit value of any.
Assistive technologies could use this hint when implementing various navigational modes,
such as "move by heading".
This token list would necessarily need to be scoped to a limited subset of keywords,
to avoid introducing extensive microformats.
feed roleWAI ARIA 1.1 defines the feed role, which
implements one solution for allowing ATs to interact with virtualized content, in the context of a scrollable list of articles.
However, feed has limitations:
table or grid.