expo/expo
Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.
30 files reviewed·August 1, 2026
More findings
Verdict
Six buttons in a row work fine for sighted testers but tell assistive tech nothing about structure. The theme half-commits to tokens, hardcoding '#fff' right next to a token-based primary, and a failed permission fetch just disappears.
Files Rams reviewed
apps/notification-tester/src/app/_layout.tsx
apps/native-component-list/src/components/Page.tsx
apps/brownfield-tester/expo-app/src/app/_layout.tsx
apps/brownfield-tester/expo-app/src/app/apis/_layout.tsx
apps/brownfield-tester/expo-app/src/app/apis/index.tsx
apps/notification-tester/src/app/index.tsx
apps/observe-tester/app/_layout.tsx
apps/router-e2e/__e2e__/01-rsc/app/_layout.tsx
apps/router-e2e/__e2e__/headless/app/_layout.tsx
apps/router-e2e/__e2e__/native-navigation/app/modals/_layout.tsx
apps/router-e2e/__e2e__/native-navigation/app/tabs/_layout.tsx
apps/router-e2e/__e2e__/native-tabs/app/_layout.tsx
apps/router-e2e/__e2e__/split-view/app/_layout.tsx
apps/router-e2e/__e2e__/stack/app/_layout.tsx
apps/router-e2e/__e2e__/web-modal/app/_layout.tsx
apps/router-e2e/__e2e__/web-modal/app/nested/page.tsx
packages/expo-sqlite/dev-plugin-webui/src/app/_layout.tsx
packages/expo-sqlite/dev-plugin-webui/src/app/index.tsx
templates/expo-template-default/src/app/_layout.tsx
templates/expo-template-default/src/app/index.tsx
templates/expo-template-tabs/app/(tabs)/_layout.tsx
templates/expo-template-tabs/app/_layout.tsx
apps/brownfield-tester/expo-app/src/app/apis/communication.tsx
apps/brownfield-tester/expo-app/src/app/apis/native-modules.tsx
apps/brownfield-tester/expo-app/src/app/apis/navigation.tsx
apps/brownfield-tester/expo-app/src/app/apis/state.tsx
apps/expo-go/ios/Client/SwiftUI/Views/AvatarView.swift
apps/expo-go/ios/Client/SwiftUI/Views/BranchDetailsView.swift
apps/expo-go/ios/Client/SwiftUI/Views/BranchesListView.swift
apps/expo-go/ios/Client/SwiftUI/Views/EmptyStateView.swift
Accessibility
apps/notification-tester/src/app/index.tsx:11
Six sequential buttons with no heading leave screen reader users guessing at grouping
The index screen stacks six React Native Buttons in a row: "Run on-device tests", "Go to NCL NotificationScreen", "Go to playground", "See Expo ui", "Go to test scenarios", and "Get Notification permissions", plus a Notifier component. Each Button carries its own visible title as its accessible name, but there's no heading or accessibility grouping distinguishing navigation actions from the permission-check action.
Why it matters
A screen reader user has to read through all six titles in sequence with no landmark or section cue, so understanding that "Get Notification permissions" is a different kind of action from the five navigation buttons takes longer than it should.
Fix
Add an accessibilityRole="header" label or wrap related buttons in a labeled View to give assistive tech a grouping structure.
<ScrollView contentContainerStyle={{ rowGap: 10, padding: 10 }}>
<Button title="Run on-device tests" onPress={() => router.push('/run')} /><ScrollView contentContainerStyle={{ rowGap: 10, padding: 10 }}>
<Text accessibilityRole="header">Navigation</Text>
<Button title="Run on-device tests" onPress={() => router.push('/run')} />Color
apps/notification-tester/src/app/_layout.tsx:48
Dark theme text and notification colors hardcode '#fff' beside a token-based primary
CustomNavigationDarkTheme sets primary from ThemeColors.dark.tint, but text and notification two lines later are raw '#fff' literals instead of any ThemeColors reference.
Why it matters
Mixing tokenized and hardcoded values in the same object means a future dark-mode palette change (e.g. an off-white text color for warmth) updates primary but leaves text and notification stuck on pure white, producing inconsistent contrast across the theme.
Fix
Source text and notification colors from ThemeColors.dark to keep every value in the theme object on the same token layer.
const CustomNavigationDarkTheme = {
...DarkTheme,
colors: {
...DarkTheme.colors,
primary: ThemeColors.dark.tint,
text: '#fff',
notification: '#fff',
},
};const CustomNavigationDarkTheme = {
...DarkTheme,
colors: {
...DarkTheme.colors,
primary: ThemeColors.dark.tint,
text: ThemeColors.dark.text,
notification: ThemeColors.dark.tint,
},
};Get this score on every PR.
Rams reviews each pull request on your repo and posts inline one-click fixes — about a minute per review.
Install Rams freeUX
apps/notification-tester/src/app/index.tsx:24
Permission fetch failure on "Get Notification permissions" vanishes silently
The onPress handler for "Get Notification permissions" calls getPermissionsAsync().then(...).catch((error) => console.error(error)). Success shows an Alert with the JSON payload, but failure only writes to the console.
Why it matters
A tester who taps the button and sees nothing happen has no way to tell if the request failed, is still pending, or if permissions were denied, so they can't distinguish a real bug from a dead tap.
Fix
Surface fetch errors to the user with the same Alert mechanism used for the success path.
getPermissionsAsync()
.then((permissions) => Alert.alert(JSON.stringify(permissions, null, 2)))
.catch((error) => console.error(error));getPermissionsAsync()
.then((permissions) => Alert.alert(JSON.stringify(permissions, null, 2)))
.catch((error) => Alert.alert('Failed to get permissions', String(error)));Typography
Spacing
Components
Motion
Craft
Working well
- Every navigation destination uses native Button components, which keep built-in press feedback and accessible names for free instead of hand-rolled Pressable divs that need manual role and label wiring.
- Forcing light mode with setColorScheme('light') is explained inline with the comment "it just looks better", so a future reader understands the override is deliberate rather than a bug to fix.
- CustomNavigationDarkTheme.colors.primary pulling from ThemeColors.dark.tint shows the token layer is set up correctly; the gaps are in the fields that don't use it yet.
Scored August 1, 2026 with Rams Engine v0.0.3 · Engine changelog
First scored July 29, 2026: 98/100. This rescore on v0.0.3: 94/100.
This page is an automated design review of expo/expo’s UI code: 30 files read against 291 versioned rules covering accessibility, color, typography, spacing, components, UX, motion, and craft. The score is out of 100; confirmed criticals cap it — one at 59, two at 49, three or more at 39.
More design scores
Score your own repo.
Free on public repos, no account. The same engine that scored this page reads your UI code and mints a score page like this one.
Public repos only. The full engine reviews the UI code and mints a public score page — we email you the link too. Already-scored repos open instantly.