Install
$ agentstack add skill-ucdavis-ai-skills-registry-accessibility-react-native ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
React Native / Expo Accessibility Skill
This skill implements and audits accessibility (a11y) in React Native and Expo apps, following WCAG 2.1 AA standards as adapted for mobile (iOS VoiceOver + Android TalkBack).
When This Skill Is Needed
Use this skill for:
- Implementing
accessibilityLabel,accessibilityHint,accessibilityRole,accessibilityState,accessibilityValue - Auditing a component, screen, or entire app for a11y gaps
- Fixing VoiceOver / TalkBack focus order and grouping
- Checking color contrast and tap target sizes
- Writing accessible custom components (modals, carousels, date pickers, etc.)
- Integrating automated a11y testing (eslint-plugin-jsx-a11y adapted for RN, react-native-a11y)
- Adding
AccessibilityInfoAPI usage (reduce motion, screen reader detection)
Core Principles
- Every interactive element must have an accessible name — via
accessibilityLabelor meaningful text child. - Every interactive element must have a role —
accessibilityRoletells screen readers what it is. - State must be announced — use
accessibilityStatefordisabled,selected,checked,expanded,busy. - Logical reading order — use
importantForAccessibility(Android) andaccessibilityViewIsModalto manage focus scope. - Tap targets ≥ 44×44 pts — per Apple HIG and Android guidelines.
- 4.5:1 contrast ratio — for normal text; 3:1 for large text and UI components.
- No information conveyed by color alone — always pair with text, icon, or pattern.
- Support Reduce Motion — gate animations behind
AccessibilityInfo.isReduceMotionEnabled().
Quick Reference: Core A11y Props
| Prop | Platform | Purpose | |------|----------|---------| | accessible | Both | Groups children into one focusable node | | accessibilityLabel | Both | Name read aloud by screen reader | | accessibilityHint | Both | Explains the result of an action | | accessibilityRole | Both | Semantic role (button, link, header, image, etc.) | | accessibilityState | Both | {disabled, selected, checked, expanded, busy} | | accessibilityValue | Both | {min, max, now, text} for sliders/progress | | accessibilityLiveRegion | Android | 'none', 'polite', 'assertive' for dynamic content | | aria-live | Both (RN ≥0.73) | ARIA-aligned live region | | accessibilityViewIsModal | iOS | Traps focus inside modal | | importantForAccessibility | Android | 'yes', 'no', 'no-hide-descendants' | | onAccessibilityAction | Both | Custom actions for screen readers | | accessibilityActions | Both | Declares custom action names |
For detailed prop usage with examples, see [references/props.md](references/props.md).
Implementation Workflow
Step 1 — Audit (find gaps)
Run the audit script to surface issues before writing any code:
node scripts/audit.js
This checks for:
- Touchable/Pressable elements missing
accessibilityLabeloraccessibilityRole - Images missing
accessibilityLabeloraccessibilityIgnoresInvertColors TextInputmissingaccessibilityLabel(separate fromplaceholder)- Custom interactive components lacking roles
- Potential color-only information (flag for manual review)
Then do a manual walkthrough with:
- iOS Simulator → Accessibility Inspector (
Xcode > Open Developer Tool > Accessibility Inspector) - Android Emulator → TalkBack (Settings > Accessibility > TalkBack)
Step 2 — Fix by component type
See [references/components.md](references/components.md) for canonical patterns for:
- Buttons & Pressables
- Text Inputs & Forms
- Images & Icons
- Lists & FlatList
- Navigation (Tab bars, Stack headers)
- Modals & Bottom Sheets
- Custom controls (Switch, Slider, Checkbox, Radio)
- Loading / Skeleton states
Step 3 — Verify color contrast
- Extract all color pairs (text + background) from your design tokens / StyleSheet.
- Run the contrast check:
node scripts/contrast-check.js - Fix any failures — see [
references/contrast.md](references/contrast.md) for replacement palette strategies.
Step 4 — Add automated testing
Install and configure:
npx expo install @testing-library/react-native
npm install --save-dev eslint-plugin-jsx-a11y
Add to .eslintrc:
{
"plugins": ["jsx-a11y"],
"extends": ["plugin:jsx-a11y/recommended"],
"rules": {
"jsx-a11y/interactive-supports-focus": "error"
}
}
Write accessibility-focused unit tests — see [references/testing.md](references/testing.md).
Step 5 — Reduce Motion & Dynamic Type
import { AccessibilityInfo } from 'react-native';
// Reduce Motion
const [reduceMotion, setReduceMotion] = useState(false);
useEffect(() => {
AccessibilityInfo.isReduceMotionEnabled().then(setReduceMotion);
const sub = AccessibilityInfo.addEventListener('reduceMotionChanged', setReduceMotion);
return () => sub.remove();
}, []);
// Dynamic Type (iOS) — use allowFontScaling (default true, do NOT set false)
...
Audit Checklist
Use this checklist per screen. Check each item; document failures with component name + line number.
Perceivable
- [ ] All images have
accessibilityLabelor are marked decorative (accessible={false}) - [ ] Color is not the only means of conveying information
- [ ] Text contrast ≥ 4.5:1 (normal) / 3:1 (large ≥18pt or bold ≥14pt)
- [ ] UI component contrast ≥ 3:1 against adjacent colors
- [ ]
allowFontScalingis NOT disabled on anyTextorTextInput
Operable
- [ ] All interactive elements have
accessibilityRole - [ ] All interactive elements have
accessibilityLabel(or unambiguous text child) - [ ] Tap targets ≥ 44×44 pts (use
hitSlopto extend without changing layout) - [ ] Focus order matches reading/visual order
- [ ] No time limits without accessible pause/extend mechanism
- [ ] Animations respect Reduce Motion setting
Understandable
- [ ] Form inputs have visible labels (not just placeholder)
- [ ] Error messages are programmatically associated with inputs
- [ ]
accessibilityHintused where action outcome isn't obvious - [ ]
accessibilityLiveRegion/aria-liveon dynamic content (toasts, errors, countdowns)
Robust
- [ ] Custom interactive components announce state changes
- [ ] Modal/overlay traps focus (
accessibilityViewIsModal={true}on iOS) - [ ] Keyboard/switch access works (external keyboard, switch control)
- [ ] No a11y props on decorative non-interactive
Views (reduces noise)
Common Mistakes to Avoid
- ❌
accessibilityLabelon aViewwrapping aTouchableOpacity(set it on the Touchable itself) - ❌ Using
placeholderas the only label forTextInput(VoiceOver reads placeholder as label, but it disappears on input) - ❌
accessible={false}on a container that has interactive children (hides them from screen reader) - ❌ Hardcoded colors that ignore dark mode / high-contrast mode
- ❌ Calling
AccessibilityInfo.announceForAccessibilityon every render (debounce or trigger only on meaningful changes) - ❌ Setting
importantForAccessibility="no-hide-descendants"on a visible interactive group
Expo-Specific Notes
- Managed Workflow: All standard RN a11y props work. No native module needed.
- expo-router: Navigation screen titles are announced automatically. Supplement with
Stack.Screen options={{ title }}for clarity. - expo-image: Supports
accessibilityLabelprop directly; userole="presentation"for decorative images. - expo-av / expo-video: Provide captions/subtitles via
subtitleStylesandtracksprops. Announce play/pause state viaaccessibilityState={{ busy: isLoading }}. - Expo Go: Accessibility Inspector works with Expo Go on physical devices.
Reference Files
| File | Contents | |------|----------| | [references/props.md](references/props.md) | Full prop API reference with before/after code examples | | [references/components.md](references/components.md) | Canonical accessible patterns for 15+ component types | | [references/contrast.md](references/contrast.md) | WCAG contrast ratios, formulas, palette fix strategies | | [references/testing.md](references/testing.md) | Unit test patterns, e2e with Detox, CI integration |
Scripts
| Script | Purpose | |--------|---------| | [scripts/audit.js](scripts/audit.js) | Static AST scan for missing a11y props | | [scripts/contrast-check.js](scripts/contrast-check.js) | Extract and validate color contrast from JS/TS files |
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: ucdavis
- Source: ucdavis/ai-skills-registry
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.