Accessibility Annotations

WebViewer Version: 8.10.0

Do you have an issue with a specific file(s)?
Can you reproduce using one of our samples or online demos?
Are you using the WebViewer server? NO
Does the issue only happen on certain browsers? Tested in Chrome & Edge
Is your issue related to a front-end framework? Yes
Is your issue related to annotations? Yes

Please give a brief summary of your issue:
We are working on a11y fixes, and we are being asked if there is a way to navigate between the elements and annotations that are in the viewer.

Please describe your issue and provide steps to reproduce it:
Create some annotations and try to focus and read on a a11y reader(NVDA) each element inside the viewer

Please provide a link to a minimal sample where the issue is reproducible:

Hello Omar,

The issue is that the annotations are drawn on the canvas of the page, so they are not accessible via regular means. However, you could leverage our APIs to add buttons to the UI that make annotations keyboard navigable.

Key APIs to do this are:

Using these APIs you could add buttons to your UI, that when clicked cycle through the annotations in doc. The buttons would be keyboard accessible. Here is a quick proof of concept to give you an idea:

Webviewer({
  constructor stuff...
}, document.getElementById('viewer')).then(instance => {

  const { documentViewer, annotationManager } = instance.Core;

  let currentAnnotations = [];

  documentViewer.addEventListener('annotationsLoaded', () => {
    // You will also need to handle the case when annotations get added by listening to the 
    // annotationChanged event in order to update the annotation list
    // Listable annotations are those that will show on the notes panel. If we don't
    // filter by these, then links will also be included in the traversal list
    currentAnnotations = annotationManager.getAnnotationsList()
      .filter(annotation => annotation.Listable);
  });


  let currentIndex = -1;
  const jumpToNextAnnotation = () => {
    if (currentAnnotations.length === 0) {
      return;
    }

    currentIndex = (currentIndex + 1) % currentAnnotations.length;
    const nextAnnotation = currentAnnotations[currentIndex];
    annotationManager.jumpToAnnotation(nextAnnotation);
    annotationManager.deselectAllAnnotations();
    annotationManager.selectAnnotation(nextAnnotation);
  }

  const jumpToPreviousAnnotation = () => {
    if (currentAnnotations.length === 0) {
      return;
    }

    currentIndex = (currentIndex - 1) < 0 ? currentAnnotations.length - 1 : currentIndex - 1;
    const previousAnnotation = currentAnnotations[currentIndex];
    annotationManager.jumpToAnnotation(previousAnnotation);
    annotationManager.deselectAllAnnotations();
    annotationManager.selectAnnotation(previousAnnotation);
  }

  instance.UI.setHeaderItems(header => {
    header.push(
      {
        type: 'actionButton',
        img: 'icon-chevron-left',
        onClick: () => jumpToPreviousAnnotation()
      },
      {
        type: 'actionButton',
        img: 'icon-chevron-right',
        onClick: () => jumpToNextAnnotation()
      }
  )});
});

Demo:

Hopefully that helps,
Best Regards,
Armando Bollain
Software Developer
PDFTron Systems, Inc.