$npx -y skills add mgifford/accessibility-skills --skill mapsLoad this skill whenever the project contains static or interactive maps, embedded map widgets (Google Maps, Leaflet, Mapbox, OpenStreetMap), or any geographic visualizations. Under no circumstances embed a map without a text-based alternative conveying the same information. Abso
| 1 | # Maps Accessibility Skill |
| 2 | |
| 3 | > **Canonical source**: `examples/MAPS_ACCESSIBILITY_BEST_PRACTICES.md` in `mgifford/ACCESSIBILITY.md` |
| 4 | > This skill is derived from that file. When in doubt, the example is authoritative. |
| 5 | |
| 6 | Apply these rules when implementing or reviewing any static or interactive map. |
| 7 | **Only load this skill if the project contains maps.** |
| 8 | |
| 9 | --- |
| 10 | |
| 11 | ## Core Mandate |
| 12 | |
| 13 | No single text description works for every map. Start with the map's purpose |
| 14 | and the tasks it supports, then provide accessible content and controls that |
| 15 | preserve that purpose for people who cannot see, distinguish, point at, drag, |
| 16 | zoom, or interpret the visual map. Keep the map and its structured |
| 17 | alternative synchronized from the same data source. |
| 18 | |
| 19 | --- |
| 20 | |
| 21 | ## Severity Scale (this skill) |
| 22 | |
| 23 | | Level | Meaning | |
| 24 | |---|---| |
| 25 | | **Critical** | Essential location data has no accessible alternative | |
| 26 | | **Serious** | Interactive map unreachable by keyboard; `role="application"` misused | |
| 27 | | **Moderate** | Skip link missing; colour independence gap; popup focus not managed | |
| 28 | | **Minor** | Missing `prefers-reduced-motion` for animations; legend incomplete | |
| 29 | |
| 30 | --- |
| 31 | |
| 32 | ## Classify the Map's Purpose First |
| 33 | |
| 34 | | Map purpose | Essential task | Common accessible presentation | |
| 35 | |---|---|---| |
| 36 | | Simple locator | Where one place is and how to reach it | Concise alt, address, landmark, directions, contact info | |
| 37 | | Location directory | Find and compare services | Searchable list/table with names, addresses, distances, categories | |
| 38 | | Route/wayfinding | Travel from A to B | Ordered directions with distances, turns, landmarks, conditions | |
| 39 | | Thematic/quantitative | Compare values across areas | Summary + data table with region names, values, units, period | |
| 40 | | Boundary/zoning | Understand containment/adjacency | Named boundary descriptions, affected locations, downloadable data | |
| 41 | | Indoor/multi-floor | Navigate a building | Floor selector, accessible route instructions, entrances/lifts/stairs | |
| 42 | | Exploratory | Investigate spatial relationships | Synchronized filters, structured results, accessible query tools | |
| 43 | |
| 44 | A map can serve more than one purpose — provide the alternatives needed for |
| 45 | every essential task rather than assuming one short `alt`, table, or |
| 46 | direction set is universally equivalent. WCAG 1.1.1's "equivalent purpose" |
| 47 | does not mean reproducing every pixel or street label — it means preserving |
| 48 | the information and tasks that matter in context. Research (the Map |
| 49 | Equivalent-Purpose Framework) found tables and turn-by-turn directions can be |
| 50 | insufficient when the purpose includes broad spatial understanding or |
| 51 | exploration — treat this as guidance, not a separate WCAG criterion, but |
| 52 | recognize when a table alone won't do. |
| 53 | |
| 54 | --- |
| 55 | |
| 56 | ## Critical: Text Alternatives for Static Maps |
| 57 | |
| 58 | ```html |
| 59 | <!-- Simple map: concise alt, details in HTML nearby --> |
| 60 | <figure> |
| 61 | <img src="clinic-location.png" |
| 62 | alt="The clinic is on the north side of King Street, immediately east of the Central Station entrance." |
| 63 | width="960" height="540"> |
| 64 | <figcaption> |
| 65 | Northside Clinic, 200 King Street. The step-free entrance is on King Street. |
| 66 | <a href="#clinic-directions">Read accessible travel directions</a>. |
| 67 | </figcaption> |
| 68 | </figure> |
| 69 | ``` |
| 70 | |
| 71 | Do not fill `alt` with turn-by-turn instructions or every road label — keep |
| 72 | it concise and put detail nearby. For complex maps, provide both a short |
| 73 | alternative AND a visible structured long description or clearly associated link: |
| 74 | |
| 75 | ```html |
| 76 | <figure> |
| 77 | <img src="accessible-transit-routes.png" |
| 78 | alt="Map of step-free transit routes in the downtown area. Detailed route information follows." |
| 79 | width="1200" height="800"> |
| 80 | <figcaption> |
| 81 | Step-free transit routes, updated 15 July 2026. |
| 82 | <a href="#transit-route-details">View route details and connections</a>. |
| 83 | </figcaption> |
| 84 | </figure> |
| 85 | ``` |
| 86 | |
| 87 | Prefer visible structured content over `aria-describedby` for complex |
| 88 | descriptions — AT generally flattens referenced headings/lists/tables into |
| 89 | one string, losing navigable structure. `alt=""` is appropriate only when |
| 90 | purely decorative or the same info is already fully available nearby — never |
| 91 | call a meaningful or interactive map decorative to hide accessibility problems. |
| 92 | |
| 93 | --- |
| 94 | |
| 95 | ## Critical: Structured Alternatives Matching the Task |
| 96 | |
| 97 | **Location list/table** (for directories): |
| 98 | |
| 99 | ```html |
| 100 | <table id="branch-table"> |
| 101 | <caption>Library branches matching the current filters</caption> |
| 102 | <thead> |
| 103 | <tr><th scope="col">Branch</th><th scope="col">Address</th><th scope="col">Distance</th><th scope="col">Accessibility information</th></t |