React Native SDK
The React Native SDK walks the React fiber tree at runtime, detects WCAG 2.2 violations, reports issues to your dashboard, and provides an optional in-app accessibility panel for end users.
Version 1.2 is the current release. Zero native module dependencies, full TypeScript support,
bundled declaration files — no @types/* package required.
Requirements
| Requirement | Minimum Version |
|---|---|
| React Native | 0.70+ |
| React | 18.0+ |
@react-navigation/native | 6.x (optional — enables auto-scan on focus) |
| iOS | 13+ |
| Android | API 21+ |
Installation
# npm
npm install @welcomingweb/react-native-sdk
# yarn
yarn add @welcomingweb/react-native-sdkNo pod install or gradle sync is required. The SDK uses only JavaScript APIs available in
React Native core.
Configuration
Call WelcomingWeb.configure() once at app startup — typically in App.tsx or index.js —
before any navigation renders.
import { WelcomingWeb } from '@welcomingweb/react-native-sdk';
WelcomingWeb.configure({
apiKey: 'YOUR_API_KEY',
appId: 'com.yourcompany.yourapp',
appVersion: '1.0.0',
environment: 'development',
autoScan: true,
debug: true,
});See the full configuration reference for every supported option.
Screen Tracking
Screen tracking is the mechanism that triggers scans. The SDK provides three complementary approaches.
withAccessibilityTracking (Higher-Order Component)
The recommended approach for most screens. Wraps your component in a tracked container that scans automatically on focus.
import { withAccessibilityTracking } from '@welcomingweb/react-native-sdk';
function HomeScreen({ navigation }) {
return <ScrollView>{/* screen content */}</ScrollView>;
}
export default withAccessibilityTracking(HomeScreen, 'HomeScreen');Behaviour: the HOC wraps your screen in a <View ref={containerRef}> with
collapsable={false}. When the screen gains navigation focus (via useFocusEffect from
@react-navigation), it waits for the configured scanDelay (default 600 ms) then an idle
callback before scanning.
If @react-navigation/native is not installed, the SDK falls back to useEffect (mount only).
Install @react-navigation/native 6.x for proper focus-based scanning.
useAccessibilityTracking (Hook)
For function components where you prefer hook composition.
import { useAccessibilityTracking } from '@welcomingweb/react-native-sdk';
export default function ProductDetailScreen({ route }) {
const a11yRef = useAccessibilityTracking('ProductDetailScreen');
return <ScrollView ref={a11yRef}>{/* screen content */}</ScrollView>;
}When using the hook, you must pass the returned ref to the root View or ScrollView. The SDK
uses this ref to access the React fiber tree for scanning.
createNavigationObserver (Fallback)
A navigation state observer for screens that don’t use the HOC or hook. Checks whether a screen is already registered before triggering a scan, so there’s no duplicate work.
import { createNavigationObserver } from '@welcomingweb/react-native-sdk';
<NavigationContainer onStateChange={createNavigationObserver()}>
{/* navigators */}
</NavigationContainer>Manual Scanning
Trigger a scan imperatively when auto-scan isn’t enough — for example, after a state change that re-renders the screen without re-focusing it.
const result = await WelcomingWeb.scanCurrentScreen();
console.log('Score:', result.summary.accessibilityScore);
for (const issue of result.issues) {
console.log(issue.severity, issue.ruleId, issue.suggestion);
}ScanResult Object
| Field | Type | Description |
|---|---|---|
screenName | string | Name of the scanned screen. |
screenRoute | string | Route path (e.g. /ProductDetail). |
componentTreeHash | string | Hash of the component tree for deduplication. |
issues | AccessibilityIssue[] | Array of detected issues. |
summary.totalComponents | number | Total nodes found in the tree. |
summary.interactiveComponents | number | Nodes with onPress, buttons, inputs, switches. |
summary.issuesBySeverity | object | { critical: N, major: N, minor: N } |
summary.accessibilityScore | number | Score from 0 to 100. |
scanDurationMs | number | Scan execution time in milliseconds. |
deduplicated | boolean | True if the scan was skipped (same tree as last scan). |
AccessibilityIssue Object
| Field | Type | Description |
|---|---|---|
ruleId | string | Unique rule identifier (e.g. mobile-touch-target-size). |
wcagMapping | string | WCAG criterion number (e.g. 2.5.8). |
wcagLevel | string | A, AA, or AAA. |
severity | string | critical, major, or minor. |
componentType | string | React Native component type (e.g. TouchableOpacity). |
componentPath | string | Full path in the tree (e.g. Home > View > Button). |
evidence | object | Measured values that triggered the issue. |
suggestion | string | Human-readable fix suggestion. |
ruleDescription | string | Brief description of the rule. |
Session Lifecycle
Development Mode
- The first scan of the day creates a new server session. The session ID is captured and reused for all subsequent scans.
- Concurrent screen scans are serialised — a shared session-ID promise ensures all scans share the same server session with no race conditions.
- When the app goes to background, the SDK calls
/scans/complete. If the request fails, the SDK retries on the next background event. - When the app resumes, the hash cache and session ID are cleared. The next scan starts a fresh session.
CI/CD Mode
Covered in full on the CI/CD integration page. In summary:
- Set
autoScan: falsein configuration. - Call
WelcomingWeb.clearScreenCache()before the scan loop. - Navigate to each screen and call
scanScreen()manually. - Call
submitScanSession()to create a session, submit all buffered scans, and complete it.
Lifecycle Management
destroy()
Release all SDK resources. Required for test teardown and safe re-configuration.
afterEach(() => {
WelcomingWeb.destroy();
});destroy() is safe to call multiple times. After calling it, configure() must be called again
before any scanning can occur.
hasScreen(name)
Returns true if the given screen name is currently registered. Used by createNavigationObserver
to avoid redundant scans.
if (WelcomingWeb.hasScreen('HomeScreen')) {
// Already tracked via HOC/hook — skip observer scan
}clearScreenCache(screenName?)
Clears stored component-tree hashes used for deduplication.
// Before a CI run — force every screen to scan fresh
WelcomingWeb.clearScreenCache();
// After fixing one screen — re-scan only that screen
WelcomingWeb.clearScreenCache('HomeScreen');TypeScript Support
The SDK ships with a bundled index.d.ts. No @types/* package is required.
import type {
ScanResult,
AccessibilityIssue,
WelcomingWebConfig,
IssueSeverity,
} from '@welcomingweb/react-native-sdk';
const result: ScanResult = await WelcomingWeb.scanCurrentScreen();Exported types: WelcomingWebConfig, ScanResult, ScanSummary, AccessibilityIssue,
IssueSeverity, SubmitSessionOptions, AccessibilityPreferences,
EffectiveAccessibilitySettings, LegacyAccessibilitySettings, AccessibilityPanelProps,
PanelFeatureId.
Troubleshooting
”Found 0 nodes” on scan
- The root
Viewmay havecollapsable={true}(default on Android). The HOC setscollapsable={false}automatically. If using the hook, addcollapsable={false}to the root view explicitly. - Screen content may not have mounted yet. The default
scanDelayis 600 ms — increase it viaconfigure({ scanDelay: 1200 })for complex screens with virtualised lists. - A React Native version change may have altered internal fiber property names. Enable
debug: trueand check for[WelcomingWeb] Could not find fiber. Keys: [...].
API returns 401 Unauthorized
Check that apiKey is correct and is passed as the X-API-Key header. If using a custom
reportingEndpoint, ensure the URL includes the full base path (/api/public/v1/mobile).
Issues not showing in Dashboard
Enable debug: true and check for [WelcomingWeb:API] Response: 200. If every response shows
deduplicated: true, the server-side dedup is incorrectly skipping across sessions.
AccessibilityPanel not visible
The panel uses absolute positioning with zIndex 9998–9999. Place <AccessibilityPanel /> as the
last child inside your NavigationContainer, after all navigators.
Scans not triggering on navigation
The SDK uses useFocusEffect from @react-navigation/native. Without it, scans only trigger on
mount. Install @react-navigation/native 6.x for focus-based scanning.
Reduce Motion toggle has no effect
The SDK does not patch Animated globally. Read effectiveSettings.reduceMotion from
useAccessibilityToolkit() and skip animations in your own components.