Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Infinite Scroll for Accessibility Test">
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,minimal-ui">
  <title>Infinite Scroll for Accessibility Test</title>
  <style>
    .item {
      margin: 16px;
      padding: 16px;
      border: 1px solid black;
    }
    .loader {
      height: 40px;
      background: #bbb;
    }
  </style>
</head>
<body>
  
  <div class="page">
    <h1>
      Infinite Scroll for Accessibility Test
    </h1>
    <div>
      Use heading navigation with VoiceOver on iOS to oberve the problem. Once you reach the last item in the list, it will start loading new items. Once new items have been loaded they will be appended to the bottom of the list. The problem is that once new items have been appended, the VoiceOver does not navigate to them via heading navigation, saying "Heading not found".
    </div>
  
  <div id="list" class="list" role="list">
    <div id="loader" class="loader">
      <div id="loader-message" class="loader-message" role="region" aria-live="polite">
      </div>
    </div>
  </div>
    
  </div>
  
  <script>
    function log(m) {
      console.log(m);
    }
    function loadingMessage(m) {
      log('Loading message: ' + m);
      var el = document.getElementById('loader-message');
      el.textContent = m;
      setTimeout(function() {
        el.textContent = '';
      }, 5000);
    }
    var itemIndex = 0;
    function generateContent() {
      var index = ++itemIndex;
      var c = '' + index;
      var item = document.createElement('div');
      item.id = 'item-' + c;
      item.setAttribute('id', 'item-' + c);
      item.setAttribute('class', 'item');
      item.setAttribute('role', 'listitem');
      
      var header = document.createElement('header');
      item.appendChild(header);
      
      var h = document.createElement('h2');
      h.setAttribute('role', 'heading');
      h.setAttribute('aria-level', '2');
      h.setAttribute('tabindex', '0');
      h.textContent = 'Item ' + c;
      header.appendChild(h);
      
      var cont = document.createElement('div');
      cont.textContent = 'Longer text content for ' + c;
      item.appendChild(cont);
      
      document.getElementById('list').insertBefore(item,
          document.getElementById('loader'));
      return item;
    }
    function generateContentList() {
      for (var i = 0; i < 2; i++) {
        generateContent();
      }
    }
    generateContentList();
    
    function getLastItem() {
      var lastItem = null;
      var children = document.getElementById('list').children;
      for (var i = 0; i < children.length; i++) {
        if (children[i].classList && children[i].classList.contains('item')) {
          lastItem = children[i];
        }
      }
      return lastItem;
    }
    
    function isLastChild(node) {
      if (!node.parentNode && !node.parentNode.parentNode) {
        return false;
      }
      var parent = node.parentNode;
      var lastItem = getLastItem();
      return (parent == lastItem || parent.parentNode == lastItem);
    }
    
    function loadMoreData() {
      log('generate more data');
      var list = document.getElementById('list');
      list.classList.add('loading');
      list.setAttribute('aria-busy', 'true');
      setTimeout(function() {
        loadingMessage('Waiting while more content is being loaded');
      }, 1000);
      setTimeout(function() {
        generateContentList();
        setTimeout(function() {
          list.classList.remove('loading');
          list.setAttribute('aria-busy', 'false');
          loadingMessage('More content has been loaded. Proceed.');
        }, 1);
      }, 5000);
    }
    document.addEventListener('focus', function(e) {
      if (isLastChild(e.target)) {
        loadMoreData();
      }
    }, true);
  </script>
</body>
</html>
Output

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
dvoytenkopro
0viewers