maps — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited maps (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Canonical source:examples/MAPS_ACCESSIBILITY_BEST_PRACTICES.mdinmgifford/ACCESSIBILITY.mdThis skill is derived from that file. When in doubt, the example is authoritative.
Apply these rules when implementing or reviewing any static or interactive map. Only load this skill if the project contains maps.
All users must access the essential information conveyed by a map through accessible alternatives, keyboard-operable controls, and clear structured content.
| Level | Meaning |
|---|---|
| Critical | Essential location data has no accessible alternative |
| Serious | Interactive map unreachable by keyboard; role="application" misused |
| Moderate | Skip link missing; colour independence gap; popup focus not managed |
| Minor | Missing prefers-reduced-motion for animations; legend incomplete |
A meaningful map with no text alternative is Critical — blind users receive no location information at all.
<!-- Simple map -->
<img src="campus-map.png"
alt="Campus map: main entrance on Elm Street,
library to the north, parking to the east.">
<!-- Complex map with extended description -->
<figure>
<img src="regional-map.png"
alt="Regional accessibility map — detailed description below."
aria-describedby="map-desc">
<figcaption id="map-desc">
<p>Three accessible transit routes through the downtown core.
Route A runs north–south on Main Street with level boarding at all stops.
Route B runs east–west on King Street. Route C is a loop serving the
waterfront. All stops marked with a wheelchair symbol.</p>
</figcaption>
</figure>Always include: purpose, key features/routes, directional relationships, meaning of colour coding or symbols.
Every interactive map must be preceded by a skip link. Users who cannot or do not wish to interact with the map must be able to bypass it. Missing skip link on an interactive map is Serious.
<a href="#map-skip-target" class="skip-link">Skip map</a>
<div id="map-container" aria-label="Interactive campus map">
<!-- map renders here -->
</div>
<div id="map-skip-target" tabindex="-1">
<h2>Map information as structured text</h2>
<!-- table or list of locations -->
</div>Google Maps, Leaflet, and Mapbox iframes are the most common real-world case. An <iframe> with no title is Serious — screen reader users cannot identify what the frame contains.
<!-- Always add a descriptive title to map iframes -->
<iframe
src="https://maps.google.com/maps?q=…&output=embed"
title="Interactive map showing our office location at 123 Main Street"
width="600" height="450"
loading="lazy">
</iframe>
<!-- Always provide a skip link before the iframe -->
<a href="#after-map" class="skip-link">Skip to location details</a>
<iframe …></iframe>
<div id="after-map">
<p>Our office: 123 Main Street. <a href="https://maps.google.com/…">
Open in Google Maps</a></p>
</div>For Leaflet and Mapbox: these libraries render into a <div> with canvas/SVG. Check the library's accessibility documentation for keyboard support options before assuming the map is operable. Leaflet has basic keyboard support; Mapbox GL JS requires additional configuration.
All mouse/touch map interactions must be keyboard-operable. An interactive map with no keyboard support is Serious.
+/- keys or accessible buttonsEnter or Space on focused markerEscape<div role="group" aria-label="Map zoom controls">
<button type="button" aria-label="Zoom in">+</button>
<button type="button" aria-label="Zoom out">−</button>
<button type="button" aria-label="Reset to default view">⟳</button>
</div>role="application" — Use with Extreme Cautionrole="application" removes the screen reader's virtual cursor (reading mode), meaning keyboard users lose the ability to navigate by headings, links, and other landmarks within the map region. All keyboard interactions must then be custom-implemented.
Only use `role="application"` when:
Misusing `role="application"` is Serious — it can strand screen reader users with no way to interact with content they could previously navigate.
<section aria-labelledby="map-heading">
<h2 id="map-heading">Service Area Map</h2>
<!-- Omit role="application" unless all interactions are fully custom-handled -->
<div aria-label="Interactive service area map">
<!-- map -->
</div>
</section><!-- Marker as accessible button -->
<button type="button"
aria-label="City Hall — open weekdays 9am to 5pm">
<svg aria-hidden="true" focusable="false"><!-- pin icon --></svg>
</button>
<!-- Popup as dialog with focus management -->
<div role="dialog"
aria-labelledby="popup-title"
aria-modal="true"
tabindex="-1"
id="city-hall-popup">
<h3 id="popup-title">City Hall</h3>
<p>123 Main Street. Open Monday–Friday, 9am–5pm.</p>
<a href="/city-hall">More information</a>
<button type="button" aria-label="Close City Hall popup">✕</button>
</div>Move focus into the popup on open. On close or Escape, return focus to the triggering marker. Apply inert to the rest of the map while the popup is open.
Never rely on colour alone for route or zone differentiation. Colour-only encoding is Moderate (Serious if the colour is the only distinction between route types with different safety or access implications).
may be overridden
<fieldset>
<legend>Map layers</legend>
<label>
<input type="checkbox" name="layer-transit" checked>
Transit routes
</label>
<label>
<input type="checkbox" name="layer-a11y">
Accessibility features
</label>
</fieldset>Announce layer changes to screen readers via aria-live="polite".
prefers-reduced-motion for Map AnimationsMap panning, zooming flyovers, and animated tile loading should respect the user preference:
const prefersReduced = window.matchMedia(
'(prefers-reduced-motion: reduce)'
).matches;
// Leaflet example
map.flyTo(latlng, zoom, {
animate: !prefersReduced,
duration: prefersReduced ? 0 : 1.5
});For maps showing a list of locations, always provide an adjacent accessible table:
<table>
<caption>Accessible library branches</caption>
<thead>
<tr>
<th scope="col">Branch</th>
<th scope="col">Address</th>
<th scope="col">Accessibility features</th>
</tr>
</thead>
<tbody>
<tr>
<td>Central Library</td>
<td>100 Main St</td>
<td>Ramp, elevator, braille signage</td>
</tr>
</tbody>
</table><figcaption>)<iframe> maps have descriptive title attributerole="application" used only if all interactions are fully custom-handledprefers-reduced-motionStandards horizon: These rules target WCAG 2.2 AA. Monitor: <https://www.w3.org/TR/wcag-3.0/>
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.