A manual accessibility evaluation of popular web map tools.
This WCAG 2.1 evaluation is to assess the accessibility support of a basic web map from each of the web map tools as implemented by the W3C Maps for HTML Community Group.
The intention of this document is to get a broad sense for the accessibility support of the evaluated web map tools. The evaluation should not be considered complete, and the results of a given Success Criterion should not be interpreted as a comparison for accessibility support between the different web map tools.
Evaluated web map tools
- Google Maps embed v3
- Google Maps Platform API v3.40
- Bing Maps embed v8
- Bing Maps Control API v8
- MapKit JS (Apple Maps) API v5.40.0
- Leaflet JS API v1.5.1
- OpenStreetMap embed v0.7.55.7
- OpenLayers API v5.3.0
- MapBox Studio embed v1.0.0
- MapBox GL JS API v4.4.1
- TomTom Maps SDK for Web v4.47.6
Environment and tools used in the evaluation
- Windows 10
- Chrome browser and dev tools v81.0.4044.122
- ChromeVox Classic Extension v53.0.2784.6
- NVDA v2019.3.1
- Accessibility Insights for Web's Visual Helper (Chrome extension v2.14.1)
Summary of the 14 evaluated WCAG Success Criteria:
Web map tool | Total | Level A | Level AA | Level AAA | ||||
---|---|---|---|---|---|---|---|---|
Failed | Applicable | Failed | Applicable | Failed | Applicable | Failed | Applicable | |
Google Maps embed | 11 | 13 | 6 | 8 | 3 | 3 | 2 | 2 |
Google Maps Platform API | 10 | 13 | 6 | 8 | 2 | 3 | 2 | 2 |
Bing Maps embed | 5 | 14 | 2 | 9 | 1 | 3 | 2 | 2 |
Bing Maps Control API | 7 | 13 | 3 | 8 | 2 | 3 | 2 | 2 |
MapKit JS (Apple Maps) API | 8 | 12 | 4 | 7 | 2 | 3 | 2 | 2 |
Leaflet JS API | 6 | 13 | 2 | 8 | 3 | 3 | 1 | 2 |
OpenStreetMap embed | 8 | 14 | 3 | 9 | 3 | 3 | 2 | 2 |
OpenLayers API | 8 | 13 | 4 | 8 | 2 | 3 | 2 | 2 |
MapBox Studio embed | 6 | 14 | 3 | 9 | 1 | 3 | 2 | 2 |
MapBox GL JS API | 7 | 13 | 3 | 8 | 2 | 3 | 2 | 2 |
TomTom Maps SDK for Web | 9 | 13 | 5 | 8 | 3 | 3 | 1 | 2 |
A summary of this evaluation was also presented (video/slides) by Nic Chan at the 2020 W3C/OGC Joint Workshop Series on Maps for the Web.
Jump to Success Criterion
- 1.1.1 Non-text Content (Level A)
- 1.3.1 Info and Relationships (Level A)
- 1.4.3 Contrast (Minimum) (Level AA)
- 2.1.1 Keyboard (Level A)
- 2.1.2 No Keyboard Trap (Level A)
- 2.1.4 Character Key Shortcuts (Level A)
- 2.4.3 Focus Order (Level A)
- 2.4.7 Focus Visible (Level AA)
- 2.5.5 Target Size (Level AAA)
1.1.1 Non-text Content (Level A)
- Identify all non-text content.
-
If non-text content is pure decoration, is used only for visual formatting, or is not presented to users, then it is implemented in a way that it can be ignored by
assistive technology (AT), (e.g. using
aria-hidden="true"
). - If the non-text content is not intended as pure decoration, it has a text alternative.
- If non-text content is a control or input, refer to the assessment of SC 4.1.2 Name, Role, Value for additional requirements.
If the requirements of step #2 and #3 are met Result is Pass, else Fail.
Web map tool | Result | Notes |
---|---|---|
Google Maps embed | Fail | The image depicting "Google" (logo) is neither hidden from ATs nor has a text alternative. |
Google Maps Platform API | Fail | The link that opens a new window to view the current location (in "Street view") is visually presented as an icon, but is missing a text alternative. |
Bing Maps embed | Pass | |
Bing Maps Control API | Pass | |
MapKit JS (Apple Maps) API | Fail | The control to change/reset the bearing has a child node with the text character "N" to convey "North", it is presumably decorative but is not hidden from ATs. |
Leaflet JS API | Pass | |
OpenStreetMap embed | Pass | |
OpenLayers API | Fail | Characters "+" and "−" of the zoom controls are decorative but are not hidden from ATs. [Github issue] |
MapBox Studio embed | Pass | |
MapBox GL JS API | Pass | |
TomTom Maps SDK for Web | Fail | Character "×" of the control to close the copyright message dialog is decorative but is not hidden from ATs. |
1.3.1 Info and Relationships (Level A)
- Verify that information (such as a control's state), structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
If requirements of step #1 is met Result is Pass, else Fail.
Web map tool | Result | Notes |
---|---|---|
Google Maps embed | Fail | The zoom controls' disabled state cannot be programmatically determined. |
Google Maps Platform API | Fail | |
Bing Maps embed | Fail | Scale bars/rulers are missing contextual information (alternatively should be hidden from ATs). |
Bing Maps Control API | Fail |
|
MapKit JS (Apple Maps) API | Fail | The web map's semantic structure as a distinct piece of content cannot be programmatically determined. |
Leaflet JS API | Fail |
|
OpenStreetMap embed | Fail | The zoom controls' disabled state cannot be programmatically determined. |
OpenLayers API | Fail |
|
MapBox Studio embed | Fail | The "Zoom out" control's disabled state cannot be programmatically determined. [Github PR] |
MapBox GL JS API | Fail | The web map's semantic structure as a distinct piece of content cannot be programmatically determined. |
TomTom Maps SDK for Web | Fail |
|
1.4.3 Contrast (Minimum) (Level AA)
-
Verify that the visual presentation of text and images of text has a contrast ratio of at least 4.5:1, except for the following:
- Large Text: Large-scale text and images of large-scale text have a contrast ratio of at least 3:1;
- Incidental: Text or images of text that are part of an inactive user interface component, that are pure decoration, that are not visible to anyone, or that are part of a picture that contains significant other visual content, have no contrast requirement;
- Logotypes: Text that is part of a logo or brand name has no contrast requirement.
If requirements of check #1 is met Result is Pass, else Fail.
Web map tool | Result | Notes |
---|---|---|
Google Maps embed | Fail | The "View larger map" link has a contrast ratio of 3.79. Some map text (i.e. ocean labels) do not mean the minimum contrast ratio. |
Google Maps Platform API | Fail | The "View larger map" link has a contrast ratio of 3.79. Some map text (i.e. ocean labels) do not mean the minimum contrast ratio. |
Bing Maps embed | Fail | Some map labels (i.e. bodies of water, district labels) do not meet the minimum contrast ratio. |
Bing Maps Control API | Fail | Some map labels (i.e. bodies of water, district labels) do not meet the minimum contrast ratio. |
MapKit JS (Apple Maps) API | Fail | Some map labels (i.e. bodies of water, minor street labels) do not meet the minimum contrast ratio. |
Leaflet JS API | Fail | Some map labels (i.e. regional/districts) do not meet the minimum contrast ratio (uses OpenStreetMap tiles). |
OpenStreetMap embed | Fail | Some map labels (i.e. regional/districts) do not meet the minimum contrast ratio (uses OpenStreetMap tiles). |
OpenLayers API | Fail | Some map labels (i.e. regional/districts) do not meet the minimum contrast ratio (uses OpenStreetMap tiles). |
MapBox Studio embed | Pass | |
MapBox GL JS API | Pass | |
TomTom Maps SDK for Web | Fail | Some map labels (i.e. buildings) do not meet the minimum contrast ratio. |
2.1.1 Keyboard (Level A)
- Identify all functionality of the web map.
- Ensure all functionality can be accessed using only a keyboard.
If the requirements of step #2 is met Result is Pass, else Fail.
Web map tool | Result | Notes |
---|---|---|
Google Maps embed | Fail |
|
Google Maps Platform API | Fail |
|
Bing Maps embed | Pass | |
Bing Maps Control API | Fail | Control to toggle area labels under "Bird's Eye view" is not keyboard accessible (has tabindex="-1" ). |
MapKit JS (Apple Maps) API | Fail | Map display is not pannable using a keyboard. |
Leaflet JS API | Pass | |
OpenStreetMap embed | Pass | |
OpenLayers API | Pass | |
MapBox Studio embed | Fail | Control to display attribution and feedback links is not keyboard accessible. [Github PR] |
MapBox GL JS API | Fail | Control to display attribution and feedback links is not keyboard accessible. [Github PR] |
TomTom Maps SDK for Web | Fail |
|
2.1.2 No Keyboard Trap (Level A)
- Sequentially navigate components using the tab key (and operate all controls).
- Check that it is possible to tab or otherwise navigate away from each component using only the keyboard.
If the requirements of step #2 is met Result is Pass, else Fail.
Web map tool | Result | Notes |
---|---|---|
Google Maps embed | Pass | |
Google Maps Platform API | Pass | |
Bing Maps embed | Pass | |
Bing Maps Control API | Pass | |
MapKit JS (Apple Maps) API | Pass | |
Leaflet JS API | Pass | |
OpenStreetMap embed | Pass | |
OpenLayers API | Pass | |
MapBox Studio embed | Pass | |
MapBox GL JS API | Pass | |
TomTom Maps SDK for Web | Pass |
2.1.4 Character Key Shortcuts (Level A)
If a keyboard shortcut is implemented in content using only letter (including upper- and lower-case letters), punctuation, number, or symbol characters, then at least one of the following is true:
- Turn off: A mechanism is available to turn the shortcut off;
- Remap: A mechanism is available to remap the shortcut to use one or more non-printable keyboard characters (e.g. ctrl, alt, etc);
- Active only on focus: The keyboard shortcut for a user interface component is only active when that component has focus.
All the web maps that have shortcuts implemented fail both check #1 and #2.
If the requirements of check #3 is met Result is Pass, else Fail.
Web map tool | Result | Notes |
---|---|---|
Google Maps embed | N/A | (No single key shortcuts available.) |
Google Maps Platform API | Pass | |
Bing Maps embed | Pass | |
Bing Maps Control API | Pass | |
MapKit JS (Apple Maps) API | N/A | (No single key shortcuts available.) |
Leaflet JS API | Pass | |
OpenStreetMap embed | Pass | |
OpenLayers API | Fail | Both the arrow keys (used to pan the map display) as well as the keyboard shortcuts + and - (to zoom) can be activated despite unrelated components having focus. |
MapBox Studio embed | Pass | |
MapBox GL JS API | Pass | |
TomTom Maps SDK for Web | Pass |
2.4.3 Focus Order (Level A)
- Determine the order of interactive elements.
- Determine the logical order of interactive elements.
- Check that the order of the interactive elements is the same as the logical order.
If the requirements of step #3 is met Result is Pass, else Fail.
(Note: This Success Criterion includes "Complementary screen reader output",
the combination of screen readers/browsers tested is not comprehensive and
different combinations may have different results. Also note that it appears
NVDA is announcing some things twice, in most cases this is because a component
has identical aria-label
and title
attribute values,
in which case it is considered a bug to announce them both, see:
nvaccess/nvda#7841.
To work around the bug, the web map tool author could use
<span title="" aria-hidden="true">
as a child element of
the control instead.)
2.4.7 Focus Visible (Level AA)
- Sequentially navigate components using the tab key (and operate all controls).
- Check that script is not used to remove focus and that each component is highlighted.
If the requirements of step #2 is met Result is Pass, else Fail.
Web map tool | Result | Notes |
---|---|---|
Google Maps embed | Fail | 2 tab stops without focus indicators. |
Google Maps Platform API | Fail | 13 tab stops without focus indicators (in "Street view"). |
Bing Maps embed | Pass | |
Bing Maps Control API | Pass | |
MapKit JS (Apple Maps) API | Pass | |
Leaflet JS API | Fail |
|
OpenStreetMap embed | Fail |
|
OpenLayers API | Pass | |
MapBox Studio embed | Fail | 1 tab stop without focus indicator. [Github PR] |
MapBox GL JS API | Fail | 1 tab stop without focus indicator. [Github PR] |
TomTom Maps SDK for Web | Fail | 2 tab stops without focus indicators. |
2.5.5 Target Size (Level AAA)
- Identify targets for pointer inputs;
-
Verify that the size of each target is at least 44 by 44 CSS pixels except when:
- Equivalent: The target is available through an equivalent link or control on the same page that is at least 44 by 44 CSS pixels;
- Inline: The target is in a sentence or block of text;
- User Agent Control: The size of the target is determined by the user agent and is not modified by the author;
- Essential: A particular presentation of the target is essential to the information being conveyed.
(Note: If you're a web map tool author wanting to conform to this SC, Lighthouse will flag targets that are smaller than 48 by 48 in CSS pixels as inappropriately sized.)
If requirements of check #2 is met Result is Pass, else Fail.
Web map tool | Result | Notes |
---|---|---|
Google Maps embed | Fail | 4/4 targets are too small. |
Google Maps Platform API | Fail | 14/14 targets are too small. |
Bing Maps embed | Fail | 3/3 targets are too small. |
Bing Maps Control API | Fail | 9/14 targets are too small. |
MapKit JS (Apple Maps) API | Fail | 5/6 targets are too small. |
Leaflet JS API | Fail | 2/2 targets are too small. [Github issue] |
OpenStreetMap embed | Fail | 2/2 targets are too small. |
OpenLayers API | Fail | 2/2 targets are too small. [Github issue] |
MapBox Studio embed | Fail | 7/7 targets are too small. |
MapBox GL JS API | Fail | 2/2 targets are too small. |
TomTom Maps SDK for Web | Fail | 3/3 targets are too small. |
3.1.1 Language of Page (Level A)
This Success Criterion is only applicable to <iframe>
embedded web maps. Refer to the assessment of SC 3.1.2 Language of Parts for establishing whether a human language can
be programmatically determined for non embedded web maps.
- Check that the
lang
attribute is specified on the<html>
element of the embedded document. - Ensure that the language code matches that of the content (which may change due to language negotiation, based on system settings).
If both step #1 and #2 is true Result is Pass, else Fail.
Web map tool | Result | Notes |
---|---|---|
Google Maps embed | Fail | |
Bing Maps embed | Pass | Specifies the corresponding ISO 639-1 code. |
OpenStreetMap embed | Fail | |
MapBox Studio embed | Pass | Specifies the corresponding ISO 639-1 code. |
3.1.2 Language of Parts (Level AA)
- Check if the
lang
attribute is set, and the specified language code matches the language of the content (which may change due to language negotiation, based on system settings).
If step #1 is true Result is Pass, else Fail.
Web map tool | Result | Notes |
---|---|---|
Google Maps embed | Fail | |
Google Maps Platform API | Fail | |
Bing Maps embed | Pass | The language of Parts can be determined as the requirements of SC 3.1.1 Language of Page are met. |
Bing Maps Control API | Fail | |
MapKit JS (Apple Maps) API | Fail | |
Leaflet JS API | Fail | |
OpenStreetMap embed | Fail | |
OpenLayers API | Fail | |
MapBox Studio embed | Pass | The language of Parts can be determined as the requirements of SC 3.1.1 Language of Page are met. |
MapBox GL JS API | Fail | |
TomTom Maps SDK for Web | Fail |
3.2.2 On Input (Level A)
- Change the setting of all components (e.g. pan and zoom the map display, change option in a drop-down menu, etc.).
- Verify that there is no automatic change of context.
If step #2 is true Result is Pass, else Fail.
Web map tool | Result | Notes | Screen capture |
---|---|---|---|
Google Maps embed | Pass | ||
Google Maps Platform API | Fail | Panning the map display using the arrow keys causes the document to scroll (in "Street view"). | View autoplaying GIF |
Bing Maps embed | Pass | ||
Bing Maps Control API | Pass | ||
MapKit JS (Apple Maps) API | Pass | ||
Leaflet JS API | Pass | ||
OpenStreetMap embed | Pass | ||
OpenLayers API | Pass | ||
MapBox Studio embed | Pass | ||
MapBox GL JS API | Pass | ||
TomTom Maps SDK for Web | Fail | Panning the map display using the arrow keys causes the document to scroll. | View autoplaying GIF |
3.2.5 Change on Request (Level AAA)
- Verify that Changes of context are initiated only by user request or a mechanism is available to turn off such changes.
If requirements of step #1 is met Result is Pass, else Fail.
Web map tool | Result | Notes |
---|---|---|
Google Maps embed | Fail | Both the "View larger map" link and the "Terms of Use" link open in new windows without warning. The "View larger map" link is especially unexpected as stylistically, it resembles a button, not a link. |
Google Maps Platform API | Fail | The "Terms of Use" link opens in new window without warning. The Google logo link contains the screen reader label "Open this area in Google Maps", which does give the user sufficient warning, as it may open in the native Maps app on mobile. |
Bing Maps embed | Fail | Both the Bing Maps logo and the "Terms" link open in new windows without warning. |
Bing Maps Control API | Fail | Both the Bing Maps logo and the "Terms" link open in new windows without warning. |
MapKit JS (Apple Maps) API | Fail |
The "Legal" link is incorrectly marked up as a button (role="button" ), opens in new tab without warning.
|
Leaflet JS API | Pass | |
OpenStreetMap embed | Fail | The "Report a problem" and "OpenStreetMap" links open in a new tab without warning. |
OpenLayers API | Fail | The "OpenStreetMap" link opens in a new tab without warning. |
MapBox Studio embed | Fail | Mapbox logo link opens in a new tab without warning. |
MapBox GL JS API | Fail | Mapbox logo link opens in a new tab without warning. |
TomTom Maps SDK for Web | Pass |
4.1.2 Name, Role, Value (Level A)
For all user interface components:
- The name and role can be programmatically determined;
- states, properties, and values that can be set by the user can be programmatically set;
- and notification of changes to these items is available to user agents, including assistive technologies.
If the requirements of all the above checks are met, Result is Pass, else Fail.
Web map tool | Result | Notes |
---|---|---|
Google Maps embed | Fail |
|
Google Maps Platform API | Fail |
|
Bing Maps embed | Fail | The "map component" (<div tabindex="0"> , which acts as a control to both zoom and pan the map display) is missing role. |
Bing Maps Control API | Fail |
|
MapKit JS (Apple Maps) API | Fail |
Control to rotate/reset the bearing is missing role. (Note: there are two separate controls providing the same functionality, for clarification, this refers to <div tabindex="0"> and not the
<input type="range" aria-label="{x} degrees"> control.)
|
Leaflet JS API | Fail |
The "map component" (<div tabindex="0"> , which acts as a control to both zoom and pan the map display) is missing name and role.
[Github issue]
|
OpenStreetMap embed | Fail | The "map component" (<div tabindex="0"> , which acts as a control to both zoom and pan the map display) is missing name and role. |
OpenLayers API | Fail |
Controls to zoom in and zoom out do not have proper names (while the title s "Zoom in" and "Zoom out" are appropriate, the child text nodes "+" and "−" takes precedence in this case, according to the
accessible name and description computation, and is announced as "button plus" and "button minus" in ChromeVox, for example).
[Github issue]
|
MapBox Studio embed | Fail | |
MapBox GL JS API | Fail | |
TomTom Maps SDK for Web | Fail |
|
- Maps' content is almost never programmatically determinable and thus not available to users of assistive technology.
-
Most controls (commonly
<a role="button">
) do not activate on both enter and space key presses (see WAI-ARIA Authoring Practices's recommended Keyboard Interactions for buttons). - Majority of web maps don't present a fullscreen button by default.
- Not all web map container elements are focusable (and enclose all their components); tabbing to the web map's components does not guarantee the map display to be fully in the user's viewport.
- There's no way to pan the map displays using a single pointer gesture.
- Available keyboard shortcuts are not conveyed to the user.
- All web maps fail to display each discrete element (country boundaries, bodies of water, roads etc.) in sharp contrast to each other (SC 1.4.11 Non-text Contrast), and none of the web maps support high contrast mode.
This document may include links to existing Github issues/PRs pertaining to a particular failure of a Success Criterion, however, it will not be updated to reflect any such fixes.
Additionally, this evaluation was reported to the web map tools' authors for awareness:
- Google Maps: https://issuetracker.google.com/issues/69541792#comment37
- Bing Maps: https://social.msdn.microsoft.com/Forums/en-US/48cac514-03ba-49d7-a91b-de9a066bb5d8/accessibility-evaluation-wcag-21?forum=bingmaps
- MapKit JS (Apple Maps): https://developer.apple.com/forums/thread/674971
- DuckDuckGo Maps: duckduckgo/community-platform#1531
- OpenLayers: openlayers/openlayers#11678
- OpenStreetMap: https://lists.openstreetmap.org/pipermail/accessibility/2020-October/000421.html
- MapBox: mapbox/mapbox-gl-js#9991
- MapLibre: maplibre/maplibre-gl-js#53
- TomTom Maps: https://devforum.tomtom.com/t/accessibility-evaluation-wcag-2-1/1400