Maps & Geospatial Data
Permalink to "Maps & Geospatial Data"Maps appear throughout data applications: sales by territory, stores near a customer, incidents by postcode, vehicles on a route. They are also among the least accessible interfaces on the web. A map’s information is positional and often colour-coded; its interactions are drag, scroll and click; its labels are frequently baked into image tiles. For a screen reader user, a typical map is a single unnamed object; for a keyboard user, it is a region the scroll wheel falls into and Tab cannot usefully enter.
This topic treats maps as data displays with the same obligations as charts: an equivalent that conveys the data, keyboard operation for exploring it, and names and announcements for its interactive parts. It covers choropleth (shaded region) maps, interactive pan-and-zoom maps, and marker and cluster maps. It is written for frontend engineers integrating map libraries such as Leaflet and MapLibre into data applications, and for designers deciding how geographic data should be presented.
It belongs to virtualization, charts & dynamic data displays.
WCAG criteria in scope
Permalink to "WCAG criteria in scope"| Criterion | Level | Relevance to maps |
|---|---|---|
| 1.1.1 Non-text Content | A | A data map needs an equivalent — usually a table plus a summary |
| 1.4.1 Use of Color | A | Colour bins and category colours need text or pattern equivalents |
| 1.4.11 Non-text Contrast | AA | Region borders, markers and focus indicators reach 3:1 |
| 2.1.1 Keyboard | A | Pan, zoom and marker activation work from the keyboard |
| 2.1.4 Character Key Shortcuts | A | Single-key map commands are active only while the map has focus |
| 2.5.7 Dragging Movements | AA | Drag-to-pan has a single-pointer alternative |
| 4.1.2 Name, Role, Value | A | Markers and clusters are named controls |
| 4.1.3 Status Messages | AA | View and filter changes are announced |
Prerequisites
Permalink to "Prerequisites"- The chart-alternative principle — data first, description second — from data visualization & chart alternatives.
- Colour-scale handling from chart colour & contrast.
- Composite-widget keyboard conventions from canvas & SVG chart keyboard interaction.
- A shared status region: role status, alert and log compared.
ARIA & HTML spec reference
Permalink to "ARIA & HTML spec reference"| Element / attribute | Valid values | When to apply | Common misuse |
|---|---|---|---|
Container role="region" + name |
aria-labelledby |
Interactive map container | role="application" over the whole map |
aria-describedby → instructions |
id | Keyboard instructions for the map | Instructions only in a help page |
tabindex="0" on container |
— | One tab stop for the map | A tab stop per marker |
Marker <button aria-label> |
place + fact | Every interactive marker | “Marker”; icon file names |
Cluster <button aria-label> |
count + area + “expand” | Marker clusters | Count only as a visual number |
| Table with caption | — | Choropleth data equivalent | alt describing colours |
role="status" |
— | View and filter changes | Announcing on every pan frame |
Step-by-step implementation
Permalink to "Step-by-step implementation"Step 1 — Provide the data equivalent (SC 1.1.1, 1.3.1)
Permalink to "Step 1 — Provide the data equivalent (SC 1.1.1, 1.3.1)"<table><caption>Revenue by region, Q1 2026</caption>…region, value, range, rank…</table>
Step 2 — Make the map one named tab stop (SC 2.1.1, 4.1.2)
Permalink to "Step 2 — Make the map one named tab stop (SC 2.1.1, 4.1.2)"<div id="map" role="region" aria-labelledby="map-h" aria-describedby="map-help" tabindex="0"></div>
Step 3 — Scope pan and zoom keys (SC 2.1.1, 2.1.4)
Permalink to "Step 3 — Scope pan and zoom keys (SC 2.1.1, 2.1.4)"el.addEventListener('keydown', (e) => { if (e.key === '+') map.zoomIn(); /* … */ });
Step 4 — Name markers and clusters (SC 4.1.2)
Permalink to "Step 4 — Name markers and clusters (SC 4.1.2)"el.setAttribute('aria-label', `${cluster.count} stores near ${cluster.placeName}, expand`);
Step 5 — Announce settled views (SC 4.1.3)
Permalink to "Step 5 — Announce settled views (SC 4.1.3)"map.on('moveend', debounce(() => status(describeView()), 400));
Keyboard interaction contract
Permalink to "Keyboard interaction contract"| Key | Context | Action | Expected AT announcement | Failure indicator |
|---|---|---|---|---|
Tab |
Page | Focus the map | “Store locations, region” + instructions | Map skipped, or a stop per marker |
| Arrow keys | Map focused | Pan | After settle: view description | Page scrolls instead |
+ / - |
Map focused | Zoom | After settle: view description | Keys fire while typing elsewhere |
0 |
Map focused | Reset view | View description | No way back |
Page Down / Page Up |
Map focused | Next / previous marker | Marker name + “3 of 14 in view” | Markers unreachable |
Enter |
Cluster | Expand | “Zoomed in: 12 stores near Rotterdam.” | Cluster not operable |
Tab |
Map focused | Leave the map | Next control | Focus trapped |
Screen reader compatibility matrix
Permalink to "Screen reader compatibility matrix"| AT + browser | Map container | Markers as buttons | View announcements |
|---|---|---|---|
| NVDA + Chrome | Named region; focus mode on Tab | Names read on Page-key focus | Read after settle |
| NVDA + Firefox | Same | Same | Same |
| JAWS + Chrome | Named region; forms mode for keys | Same | Same |
| VoiceOver + Safari | Region; VO keys may need pass-through | Same | May be dropped mid-animation — debounce |
| TalkBack + Chrome | Explore by touch reaches markers | Named markers readable | Read |
Edge cases & failure modes
Permalink to "Edge cases & failure modes"1. Labels baked into tiles
Permalink to "1. Labels baked into tiles"Diagnosis: place names exist only in raster or vector tile images. Fix: supply names in marker labels, list items and view announcements.
2. Scroll wheel captured by the map
Permalink to "2. Scroll wheel captured by the map"Diagnosis: scrolling the page zooms the map instead. Fix: cooperative gestures or wheel zoom only after the map is engaged.
3. Re-clustering destroys focus
Permalink to "3. Re-clustering destroys focus"Diagnosis: zooming re-forms clusters and removes the focused marker. Fix: move focus to the container or the nearest new item after re-clustering.
4. Colour-only choropleth legend
Permalink to "4. Colour-only choropleth legend"Diagnosis: bins defined only by shade. Fix: text ranges in the legend and a Range column in the table.
5. Global single-key bindings
Permalink to "5. Global single-key bindings"Diagnosis: the library binds + and - on the document; typing in a search box zooms the map. Fix: disable the library handler and scope keys to the focused container.
Cross-cutting concerns
Permalink to "Cross-cutting concerns"The map is rarely the whole feature. Most maps in data applications sit next to something else: a table of regions, a list of results, a filter panel, a detail pane. Accessibility is easiest when those companions are designed as first-class views rather than afterthoughts. A store locator whose list is sortable by distance and filterable by opening hours is fully usable without the map; the map then adds orientation for users who can use it, rather than being a gate everyone must pass through.
Geography needs words. Positions on a map are meaningless to users who cannot see it unless they are expressed in terms people use: place names, distances, directions, administrative areas. Every view announcement, marker name and summary should use those terms. A reverse-geocoding step — nearest town for the map centre, neighbourhood for a marker — is often the most valuable accessibility investment on a map feature.
Library defaults vary widely. Leaflet ships keyboard panning and focusable markers with alt text options; MapLibre leaves markers entirely to you; commercial SDKs differ again. Audit the defaults of whichever library you use: whether keys are bound on the document or the container, whether markers are focusable, whether controls are buttons with names, and whether attribution links and logos are reachable.
Performance and the accessibility tree. A map with thousands of DOM markers is slow for screen readers in the same way a large table is. Clustering keeps the rendered count down; the synchronised list should be paginated or virtualised for the same reason — see pagination versus virtualization for large tables.
Motion. Animated fly-to transitions, pulsing markers and auto-panning to follow a vehicle can trigger vestibular symptoms and make it hard to keep track of focus. Respect prefers-reduced-motion by jumping instead of flying, and avoid continuous animation of markers.
Touch screen readers. VoiceOver on iOS and TalkBack on Android let users explore the map by touch, which reaches DOM markers but not tile content. Named markers and a list view are what make touch exploration productive; pinch-zoom gestures are handled by the screen reader and should not be relied on as the only way to zoom.
Choropleth table alternatives
Permalink to "Choropleth table alternatives"Table alternatives for choropleth maps builds the region table, writes colour bins as text, and generates a summary of extremes and geographic patterns from the same data as the map.
summarise(rows, regionMeta); // "North highest at €410k; 1 region in the high band."
Behaviour note: sorting by value by default puts the map’s main message first.
Keyboard panning and zooming
Permalink to "Keyboard panning and zooming"Keyboard panning and zooming for interactive maps gives the map one tab stop, scoped arrow and zoom keys, visible buttons, a scroll-wheel fix, and a settled view description.
map.on('moveend', debounce(describeView, 400));
Behaviour note: avoid role="application"; scoped keys on a named region give control without removing reader commands.
Markers and clusters
Permalink to "Markers and clusters"Announcing map markers and clusters turns markers and clusters into named buttons, steps through them nearest-first, and synchronises the map with a list of places in view.
el.setAttribute('aria-label', `${store.name}, ${store.openText}`);
Behaviour note: the list is usually the fastest way to browse; the map answers spatial questions.
Who these decisions affect
Permalink to "Who these decisions affect"Blind and low-vision users get the data from the equivalent: the table, the summary, the list. For many, the map adds little; for others with some vision, it adds geography once they can pan and zoom it.
Keyboard-only users need the map to be reachable, operable and escapable, and markers to be reachable without dozens of Tab presses.
Users of screen magnifiers see a small window of the map; view announcements and a list keep them oriented when they cannot see the whole map at once.
Colour-vision deficiency affects choropleth reading directly; text ranges and patterns make the classification available without colour.
Where to start on an existing map feature
Permalink to "Where to start on an existing map feature"Maps are often built once and left alone, so the retrofit order matters:
- The equivalent. Add the table (for choropleths) or the list (for markers) first. It is plain HTML, it helps every user, and it makes the feature usable by screen reader users immediately, whatever state the map is in.
- The name and instructions. Give the map container a name and a short line of keyboard instructions linked with
aria-describedby. - Scoped keys. Check where the library binds its keyboard handler. If it is on the document, turn it off and install your own on the container.
- Zoom buttons. Make sure zoom in, zoom out and reset are real, named buttons — some libraries render them as links or unnamed icons.
- Markers. Turn markers into named buttons without tab stops and add Page-key stepping.
- Announcements. Add the debounced view description, then cluster and filter messages.
Steps one and two alone move a map from unusable to usable for most screen reader users; steps three to six make the map itself explorable for keyboard users.
Design system integration
Permalink to "Design system integration"| Component | Accessible behaviour | Criterion |
|---|---|---|
| MapContainer | Named region, instructions, scoped keys, controls, settle announcements | 2.1.1, 2.1.4, 4.1.3 |
| Marker / Cluster factories | Named buttons, no tab stop, stepping order | 4.1.2, 2.4.3 |
| MapList | Synchronised list of items in view | 1.1.1, 1.3.1 |
| ChoroplethTable | Region table with text bins and generated summary | 1.1.1, 1.4.1 |
| Map tokens | Borders, markers and focus at 3:1 in both themes | 1.4.11 |
Testing checklist
Permalink to "Testing checklist"Automated
Permalink to "Automated"Keyboard
Permalink to "Keyboard"Screen reader
Permalink to "Screen reader"FAQ
Permalink to "FAQ"How do I make a map accessible to screen reader users?
Provide the map’s data in an accessible form — a table of regions and values or a list of places — with a short summary of the pattern, and make the interactive map itself keyboard operable with named markers and announced view changes.
Is alt text enough for a data map?
No. A name or description of the picture does not give users the values. The data behind the map, as a table or list, is the equivalent.
Do map tiles need text alternatives?
The tiles themselves are background imagery and can be treated as decorative, but any information they carry that users need — place names, boundaries, points of interest — must be available in text through markers, lists or announcements.
How should a route map be made accessible?
Provide the route as an ordered list of steps with distances and turn directions, and keep it synchronised with the highlighted segment on the map. The list is the primary way to follow a route by keyboard or screen reader.
Can a map be the only way to find a location?
It should not be. Offer search by name or postcode and a sortable list, so users who cannot operate or see the map can still find what they need directly.
Should maps use role="application"?
Usually not. Use a named region with keyboard handling scoped to the focused map, so screen reader users keep their reading commands.
Related
Permalink to "Related"- Chart alternatives — the same equivalence principle
- Chart colour & contrast — colour scales on maps
- Chart keyboard interaction — stepping through points
- Data dashboards — maps as dashboard widgets
- Keyboard shortcuts — scoping map keys