Slack — Android VPAT journey¶
Summary¶
Slack Engineering retrospective (2025-11-19) on how the Slack Android team triaged and resolved accessibility issues surfaced by a 2024 third-party VPAT (Voluntary Product Accessibility Template) audit conducted after the IA4 UI redesign. The post walks eight recurring issue themes (7 resolved, 1 deferred as future work), names the Android-platform-specific resolution for each, and calls out where WCAG mappings do not apply cleanly to Android-native patterns. Canonicalises three reusable mobile- a11y patterns and a new concept for the VPAT audit artifact itself. Borderline Tier-2 include — mobile UX / accessibility engineering rather than distributed systems internals proper — admitted on user explicit "Full ingest... No shortcuts" override and on pattern- canonicalisation grounds consistent with the 2025-01-07 Slack automated-accessibility-testing ingest.
Key takeaways¶
- VPAT as triage driver — Slack commissioned a third-party VPAT audit in 2024 after the IA4 redesign. The "shovel-ready" issues (colour contrast, missing image labels) were assigned out immediately; the remaining issues were grouped into eight recurring themes and triaged. The structure of the post is the theme list itself: P1 errors-inaccessible, P1 heading-not- identified, P2 missing-a11y-label-on-EditField, P2 incorrect- number-of-list-items, P2 drag-and-drop-inaccessible, P2 strikethrough-not-conveyed, P3 errors-indicated-by-color-alone, P3 keyboard-navigation-and-focus (deferred). (Source: sources/2025-11-19-slack-android-vpat-journey)
- Accessibility delegate override is the Android mechanism for
fixing framework-semantic bugs — the "incorrect number of list
items" issue was caused by Slack Kit's
SK divider(purely decorative) being counted as a list item by TalkBack'sCollectionInfo. A bottom sheet with 7 rows + 2 dividers would announce "7 items in a list" instead of 5. Fix: introduce a newSKListAccessibilityDelegateforSKListAdapter, overriding the a11yCollectionInfowith the correct number of items. This canonicalises [[patterns/accessibility-delegate-override-for- semantic-fix]] — the Android a11y framework'sAccessibilityDelegatesubclass is the load-bearing extension point for correcting semantically-wrong framework defaults without changing the underlying widget tree. (Source: [[sources/2025-11-19-slack-android-vpat- journey]]) - Custom TalkBack actions are the answer when a gesture cannot be
made accessible — the workspace switcher's drag-and-drop
rearrangement was inaccessible to users lacking the dexterity or
vision to drag. Slack's fix has three layers: (a) an explicit
Edit mode toggle that reveals six-dot drag handles (visual
affordance — before the toggle there was no UI cue that workspaces
were draggable); (b) custom TalkBack actions "Move before"
and "Move after" accessible via three-finger tap or
L/rdrawing gesture on a row; (c) Done button to dismiss Edit mode. Canonicalises [[patterns/custom-talkback-actions-as-gesture- alternative]] — on Android, every gesture-only interaction should have an equivalent exposed throughAccessibilityNodeInfoCompat.addAction(...)so TalkBack users can invoke it from the context menu. (Source: [[sources/2025-11-19- slack-android-vpat-journey]]) - Errors must be announced, not just displayed — the P1 "Error
messages are inaccessible" theme: if a user enters invalid input
and presses Next, an error text appears but TalkBack does not
announce it; users must sweep through the screen to find the error.
Slack fixed both display paths: (a) inline errors under the field
(
OutlinedTextFieldmodified so the error announces when focus returns), (b) banner errors (SKBannerupdated so the error type auto-announces to screen readers). Canonical takeaway: "One crucial lesson learned is the importance of immediately announcing errors to screen reader users. This eliminates the need for them to navigate through screens to understand the outcome of their actions." (Source: [[sources/2025-11-19-slack-android-vpat- journey]]) - Redundant error signalling — never colour alone — the P3 theme (WCAG 1.4.1, Level A): error text was rendered red under the field, but users unable to perceive red saw it as indistinguishable from normal copy. Fix: add an error icon alongside the red text. "While it's a relatively minor change, it improves the intuitiveness of understanding error messages." Canonicalises concepts/redundant-error-signalling — the dual-encoding discipline (colour + icon + text + announce) that defeats the "colour alone" anti-pattern on all platforms. (Source: sources/2025-11-19-slack-android-vpat-journey)
- WCAG does not apply cleanly to Android native patterns — the vendor suggested that titles in the top app bar should be marked as headings (per WCAG 1.3.1 info-and-relationships). Slack tested native Google apps and found this pattern is not the Android convention; they closed those tickets. Strikethrough-in- screen-reader was similarly closed after consulting the blind community: "Most screen readers don't interpret this format because doing so making it verbose and potentially confusing for screen reader users." Canonicalises concepts/wcag-platform-applicability-gap — WCAG is web-centric; platform-native a11y conventions sometimes legitimately diverge and require judgment-based triage rather than mechanical mapping. (Source: sources/2025-11-19-slack-android-vpat-journey)
- Keyboard navigation deferred as out-of-scope for current form-factor — the P3 keyboard-nav theme was explicitly not planned because Slack Android does not yet support large form factors (tablets), which is the primary surface where keyboard navigation matters. "We have decided to explore other solutions that align with recommended practices and standards." Canonical instance of scope-bounded deferral with documented rationale — not all WCAG criteria apply to all contexts, and explicitly- documented-deferral is a legitimate VPAT response. (Source: sources/2025-11-19-slack-android-vpat-journey)
- Design-team collaboration is load-bearing — Slack repeatedly calls out that a11y-minded design partners unblocked decision- making: Edit-mode toggle for drag-and-drop, search-icon labelling for the search field, strikethrough-no-op decision. "Collaborating with our a11y-minded design team greatly facilitated the decision- making process and issue resolution." (Source: [[sources/2025-11- 19-slack-android-vpat-journey]])
VPAT resolution table (summary)¶
| Issue | WCAG | Android mechanism | Resolution |
|---|---|---|---|
| Errors not announced to screen reader | 4.1.2 Name, Role, Value (A) | Modify OutlinedTextField and SKBanner to announce on error |
✅ |
| Heading not identified in lists | 1.3.1 Info and Relationships (A) | Mark list headings; top-app-bar title not treated as heading (platform convention) | ✅ (partial — top-app-bar deferred) |
| Missing a11y label on EditField | 4.1.2 Name, Role, Value (A) | Add explicit icon (magnifying glass) for search field; AMI left as-is due to space | ✅ |
| Incorrect list item count | 1.3.1 Info and Relationships (A) | SKListAccessibilityDelegate overrides CollectionInfo count, excluding SK divider decorative items |
✅ |
| Drag-and-drop workspace switcher inaccessible | 2.5.7 Dragging Movements (AA) | Edit-mode toggle + six-dot drag handle visual + custom TalkBack "Move before"/"Move after" actions | ✅ |
| Strikethrough not conveyed | 1.3.1 Info and Relationships (A) | Closed after consulting blind community — verbosity cost > benefit; recommend authors avoid strikethrough | ✅ (no-op by design) |
| Errors by colour alone | 1.4.1 Use of Color (A) | Add error icon alongside red text | ✅ |
| Keyboard navigation and focus | 2.1.1 Keyboard (A), 2.1.2 No Keyboard Trap (A) | Not planned — Slack Android has no large-form-factor support yet | ⏳ |
Systems / concepts / patterns extracted¶
Systems¶
- systems/slack-android (new) — Slack's Android native client; anchor for Android-specific architectural disclosures.
- systems/slack-kit (new) — Slack's shared mobile component
library (named SK in the post:
SKBanner,SKList,SKListAdapter,SK divider, and the newSKListAccessibilityDelegate). - systems/talkback (new) — Android's built-in screen reader; the canonical assistive-tech surface against which the VPAT issues manifested.
- systems/android-accessibility-framework (new) — Android's a11y
APIs (
AccessibilityDelegate,AccessibilityNodeInfoCompat,CollectionInfo, custom-action API) that the Slack fixes plug into.
Concepts¶
- concepts/vpat-voluntary-product-accessibility-template (new) — the VPAT audit artifact as a triage-driver; how a third-party vendor audit turns into an engineering backlog.
- concepts/wcag-platform-applicability-gap (new) — WCAG standards are web-centric; platform-specific a11y conventions sometimes diverge, and judgment-based triage is the legitimate response rather than mechanical mapping.
- concepts/redundant-error-signalling (new) — the never- colour-alone discipline; pair colour with icon, text, and an announced event.
- concepts/automated-vs-manual-testing-complementarity (existing, extended) — the VPAT audit is the manual / third-party / periodic layer in Slack's broader a11y strategy, complementing the 2022-launched automated Axe-Core-in-Playwright CI suite (see [[sources/2025-01-07-slack-automated-accessibility-testing-at- slack]]).
Patterns¶
- patterns/accessibility-delegate-override-for-semantic-fix (new)
— override Android's
AccessibilityDelegateto correct framework- semantic defaults without changing the widget tree; canonical instance is Slack'sSKListAccessibilityDelegatefixing the decorative-divider list-count bug. - patterns/custom-talkback-actions-as-gesture-alternative (new) — any gesture-only interaction must be re-exposed as a custom TalkBack action accessible from the context menu; pair with a visual affordance (Edit-mode toggle + drag handle) for sighted motor-impaired users.
- patterns/vpat-driven-a11y-triage (new) — the end-to-end workflow: commission third-party VPAT audit → triage into themes → resolve, defer (with rationale), or reject (with platform-convention rationale); rejections are legitimate outputs.
Operational numbers / architectural details¶
- VPAT audit date: 2024 (post-IA4 redesign).
- Vendor: unnamed third-party a11y vendor.
- Platform coverage: Android, iOS, desktop all audited; this post covers Android only.
- Theme count: 8 recurring themes on Android (7 resolved, 1 deferred).
- WCAG version: 2.1 (Level A and AA criteria cited — 4.1.2, 1.3.1, 2.5.7, 1.4.1, 2.1.1, 2.1.2).
- Slack Kit components touched:
OutlinedTextField,SKBanner,SKListAdapter,SKListAccessibilityDelegate(new). - TalkBack custom-action invocation mechanisms: three-finger
tap on a row item,
L(upward) orr(downward) drawing gesture. - Future VPAT cadence: "the timing of our next VPAT assessment is yet to be determined."
Caveats¶
- No disclosure of how many total VPAT tickets were filed, how many were "shovel-ready" (colour contrast, missing labels), or the size of the remaining triage backlog that generated the 8 themes.
- No timeline disclosure for the fixes (year 2024 onward is implied but not quantified); no engineering-hour estimates.
- No mention of automated regression coverage for the fixes — implicit coupling to the [[sources/2025-01-07-slack-automated-accessibility-testing-at- slack|Slack automated Axe-in-Playwright CI suite]] is plausible but not stated.
- iOS and desktop VPAT findings / resolutions are not in scope of this post.
- Keyboard-navigation deferral is rationalised on form-factor grounds but leaves an open WCAG-A (2.1.1 Keyboard) non- conformance on screen.
- No disclosure of the vendor's methodology, tooling, or the distinction between automated-findings vs manual-findings in the vendor's report.
- Strikethrough-is-no-op is a considered call, but does carry the WCAG 1.3.1 ticket closed without remediation; users who do want strikethrough announced have no fallback beyond turning on verbose modes in their specific screen reader.
Source¶
- Original: https://slack.engineering/android-vpat-journey/
- Raw markdown:
raw/slack/2025-11-19-android-vpat-journey-20e80756.md
Related¶
- sources/2025-01-07-slack-automated-accessibility-testing-at-slack — Slack's automated Axe-in-Playwright CI integration; the automated-testing-layer complement to this VPAT third-party- manual-audit layer.
- companies/slack — Slack company page.
- concepts/automated-vs-manual-testing-complementarity — why both this post's manual VPAT layer and the 2025-01-07 post's automated Axe layer are necessary.
- concepts/wcag-2-1-a-aa-scope — the WCAG scope this audit also used.