ArcGIS Blog

Developers

ArcGIS Maps SDK for JavaScript

Build accessible web apps with ArcGIS Maps SDK for JavaScript and Calcite Design System

By Kitty Hurley and Jessica McCall

Basemap zoom focused on the city of New Braunfels, Texas.

What is web accessibility?

Web accessibility is the practice of removing barriers that may prevent people from fully experiencing content and supporting inclusion for individuals with disabilities. It can be a complex process to create fully accessible web solutions as the manner of which an individual interacts with the web can vary greatly from person to person 

However, we can look to the Web Content Accessibility Guidelines, or WCAG, as a guide to improve accessibility on the web. WCAG serves as an internationally recognized coding standard, developed to meet the varying needs of individuals, organizations, and government agencies implementing web accessibility. WCAG’s success criterion provide standards for developers of web and mobile content when publishing web content or apps.

Building accessibility into web maps

Esri’s commitment to accessibility is evident in the development of accessible components in JavaScript Maps SDK and Calcite, which aim to provide building blocks to design an accessible UI. Below are some ways to build accessible and inclusive apps with JavaScript Maps SDK and Calcite.

Color contrast

Color contrast is key for individuals who may have low vision, macular degeneration due to age, color vision deficiency (color blindness), or a variety of other vision-related impairments. Being aware of the contrast of colors or specific combinations of colors is key to creating an accessible web app. WCAG Success Criterion 1.4.3: Contrast (Minimum) aims for a 4.5 to 1 ratio when visually presenting text and images.

Enhanced color contrast with Calcite’s web components

Calcite’s colors support WCAG Success Criterion 1.4.3: Contrast (Minimum), or level AA.

You can add further support with WCAG Success Criterion 1.4.6: Contrast (Enhanced), or level AAA, as an example, by updating the CSS variable of calcite-ui-danger to provide a contrast ratio greater than 7 to 1, where the background color is white or #FFF:

body { 
  --calcite-ui-danger: #A92519; 
}
Calcite's Input and Input Message components color can be modified to support higher contrast ratios for your audience.
Calcite's Input and Input Message components color can be modified to support higher contrast ratios for your audience.

High contrast mode

High contrast modes can be enabled on an operating system (OS), where colors are forced and visual elements are simplified. High contrast mode supports individuals who may have low vision or are unable to distinguish shapes or details in objects.

Add contrast to maps

You can add high contrast basemaps, toggle control themes, and update graphic colors to showcase solutions to a wider audience while supporting the success criterion.

Toggle between high contrast basemaps

Switch between high contrast light and dark basemaps using the BasemapToggle widget.

To do this, start by adding the high contrast basemaps as objects:

const highContrastLightBasemap = new Basemap({
  portalItem: {
    id: "084291b0ecad4588b8c8853898d72445"
  },
  title: "High contrast light theme",
  id: "high-contrast-light"
});

const highContrastDarkBasemap = new Basemap({
  portalItem: {
    id: "3e23478909194c54992eaaee78b5f754"
  },
  title: "High contrast dark theme",
  id: "high-contrast-dark"
});

Next, set the map’s basemap property to the light basemap.

const map = new Map({ 
  basemap: highContrastLightBasemap 
});

Then add the BasemapToggle widget with the nextBasemap set to the dark basemap:

const baseToggleWidget = new BasemapToggle({ 
  view: view, 
  nextBasemap: highContrastDarkBasemap, 
  container: baseToggleDiv 
});

Finally, toggle the JS Maps SDK theme for additional contrast on the controls. For instance, when the high contrast light basemap is active, the JS Maps SDK theme is dark:

const baseToggleDiv = document.getElementById("baseToggleDiv");

baseToggleDiv.addEventListener("click", () => { 
  const lightTheme = document.getElementById("darkTheme"); 
  const darkTheme = document.getElementById("lightTheme"); 
  lightTheme.toggleAttribute("disabled"); 
  darkTheme.toggleAttribute("disabled"); 
});

Customize graphics by basemap theme

To style graphics added to the map with an appropriate color contrast ratio of the basemap, first obtain the basemap background color using getBasemapBackground and getBasemapColorand use the value.

Use reactiveUtils to watch when the basemap’s background theme color changes from light to dark, or vice versa. An AbortController signal can be used to communicate, or abort a request in the DOM, in this case when the view is no longer updating.

Once the view has finished updating, use getBackgroundColorTheme and based on the light or dark value, update the graphic’s symbol color.

let abortController = null;

const basemapHandle = reactiveUtils.watch(
  () => view.map.basemap,
  () => onBasemapChange(),
  { initial: true }
);

// Remove watch handle when view is destroyed
view.addHandles(basemapHandle);

async function onBasemapChange() {
  abortController?.abort();
  const { signal } = (abortController = new AbortController());

  await reactiveUtils.whenOnce(() => !view.updating, signal);

  // getBackgroundColor is also available
  const backgroundTheme = await colorUtils.getBackgroundColorTheme(view);
  const color = backgroundTheme === "light" ? lightColor : darkColor;

  locate.graphic.symbol.color = color;
  if (hasLocation) {
    // We already have a graphic. Let's recreate
    view.graphics.removeAll();
    locate.locate();
  }
}

Navigating through content

Focus attributes, which is the practice of underlining, highlighting or placing a shape around an active element, are important to accessibility because it shows people where they are on the screen and provides context in navigation as well as supporting better keyboard navigation. WCAG Success Criterion 2.4.3: Focus Order ensures users can navigate sequentially through content, including operation with a keyboard.

Add focus to popups on open

Use the shouldFocus option to shift focus to the popup on Popup.open.

When using the Popup‘s open method, use the shouldFocus option to shift focus to the popup when opened.

view.popup.open({ 
  location: event.mapPoint, 
  shouldFocus: true 
});

Search widget focus

Shift focus between the search widget and the search results popup with reactiveUtils. Upon closing the results popup, focus will shift back to the search widget so users can navigate sequentially while searching the map's content.

When the popup is visible, set focus to the popup from the search widget using the search-complete event.

First, create a promise with the reactiveUtils whenOnce() method and an AbortController signal when the popup is visible. Once visible, shift focus to the popup.

A second promise waits for the popup to no longer be visible, where focus will be set back to the search widget.

search.on("search-complete", () => onSearchComplete());

let abortController = null;
    
async function onSearchComplete() {
  abortController?.abort();
  const { signal } = (abortController = new AbortController());

  // When the popup is visible set focus on it.
  await reactiveUtils.whenOnce(() => view.popup.visible, signal);
  view.popup.focus();

  // And when the popup is closed move the focus back to the search widget.
  await reactiveUtils.whenOnce(() => !view.popup.visible, signal);
  search.focus();
}

Animations

People who may suffer from vestibular disorders or have suffered from traumatic brain injury and can be triggered by animations may consider choosing settings on their OS and browser to reduce animations and other interactive elements that could induce headaches, nausea, or seizures. WCAG Success Criterion 2.3.3: Animation from Interaction allows the user to disable interactions, unless animation is an essential function for the information conveyed.

Reduced motion support with Calcite's loader component

Calcite minimizes animation when system animations are turned off or reduced. When animations are enabled, animations are executed in Calcite's loader component. When animations are turned off or reduced, animations are greatly reduced.

Prefers reduced motion with JavaScript Maps SDK

Animation on the map can be reduced when animations are not shown or reduced with prefers-reduced-motion. When animations are enabled, some of the map's functions, such as zooming to a feature, include basemap tile animations. When animations are turned off or reduced, a function can be added to reduce map animations.

First, add the goToOverride function to the popup’s goTo method:

view.popup.goToOverride = goToOverride;

Next, add a new function to set a media query to the prefers-reduced-motion CSS media feature, which when animation is disabled on the OS will minimize non-essential motion in the map for users:

function goToOverride (view, goToParams) { 
  const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)"); 
  if (mediaQuery.matches) { 
    goToParams.options = { 
      ...goToParams.options, 
      ...{ 
        animate: false, 
      }, 
    }; 
  } 
  return view.goTo(goToParams.target, goToParams.options); 
}

Explore further

Content above has been summarized from the 2023 Developer Summit’s “Building Accessible Web Apps with ArcGIS Maps SDK for JavaScript and Calcite Design System” session in Palm Springs, California.

The code and full demonstrations are available on GitHub. You can stay up to date on accessibility updates by subscribing to our Accessibility community.

Final thoughts

We’re here to support you in the successful implementation of accessible mapping apps. As developers and designers create web and mobile content, it is more efficient to include accessibility throughout the development lifecycle rather than having to rework published apps.

Accessibility should not be an afterthought and be a part of the development process throughout the app’s design and development workflow. But to get to this level of success, we must work together to break down barriers so that anyone who needs access to web maps, whether as a developer or a user, can obtain it.

Share this article

Subscribe
Notify of
0 Comments
Oldest
Newest
Inline Feedbacks
View all comments