
Expo Ios Hig Verify
- 70 installs
- 191 repo stars
- Updated July 24, 2026
- pproenca/dot-skills
expo-ios-hig-verify is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
Key points
- expo-ios-hig-verify
- AI & Agent Building
- AI-coding skill
Expo Ios Hig Verify by the numbers
- 70 all-time installs (skills.sh)
- +7 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #5,726 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/pproenca/dot-skills --skill expo-ios-hig-verifyAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 70 |
|---|---|
| repo stars | ★ 191 |
| Last updated | July 24, 2026 |
| Repository | pproenca/dot-skills ↗ |
How do I helps with ai & agent building tasks during ai-assisted development?
Helps with ai & agent building tasks during AI-assisted development.
Who is it for?
Best when you're working on ai & agent building and need structured help with expo-ios-hig-verify.
Skip if: Teams with no ai & agent building needs, or anyone wanting a generic chat assistant without this specific workflow.
When should I use this skill?
When you need to helps with ai & agent building tasks during ai-assisted development, or when expo-ios-hig-verify is a claude code skill for ai & agent building. it helps solo builders move faster with ai-assisted codin
What you get
Structured output aligned to expo-ios-hig-verify: expo-ios-hig-verify; AI & Agent Building; AI-coding skill.
Files
Expo iOS HIG Verifier
A read-only static checker that scans an Expo (React Native) project for violations of the expo-ios-hig rules and reports them grouped by severity, with file:line locations and links to the rule that explains the fix. It is the automated counterpart to the expo-ios-hig reference skill: that skill teaches the rules; this one checks them.
When to Apply
Run this skill when:
- The user asks to check, lint, audit, or review an Expo app for HIG compliance or native feel
- Before merging or shipping Expo iOS UI changes, as a quality gate
- After scaffolding new screens, to confirm they stay native
- Investigating why an Expo app "feels like a web wrapper" or "feels like Android"
It is read-only — it never modifies the target project, so it is safe to run unsupervised.
Workflow Overview
verify-hig.sh [project-dir]
1. Resolve search roots (app/ src/ components/ by default, or config.json)
2. Run static checks — one per detectable expo-ios-hig rule (rg, or grep fallback)
3. Aggregate findings: severity, rule, message, file:line
4. Print grouped report (ERRORS then ADVISORIES) with a link to each rule
5. Exit 0 if clean, 1 if any ERROR (with --strict, advisories fail too)Run it:
bash scripts/verify-hig.sh /path/to/expo-app # text report
bash scripts/verify-hig.sh /path/to/expo-app --strict # advisories also fail
bash scripts/verify-hig.sh /path/to/expo-app --json # machine-readableChecks
ERRORS are high-precision (import and literal-flag matches, low false positives). ADVISORIES are heuristics that warrant a look but don't fail the run unless --strict.
| Severity | Rule | Detects |
|---|---|---|
| ERROR | native-avoid-material-ui | react-native-paper, @react-native-material/*, @rneui/*, react-native-elements imports |
| ERROR | nav-native-stack | @react-navigation/stack / createStackNavigator |
| ERROR | touch-gesture-handler-thread | PanResponder |
| ERROR | touch-pressable-feedback | TouchableWithoutFeedback |
| ERROR | acc-dynamic-type | allowFontScaling={false} |
| ERROR | motion-ui-thread-animation | useNativeDriver: false |
| ADVISORY | nav-native-tabs | createBottomTabNavigator (JS tab bar) |
| ADVISORY | visual-semantic-colors | hardcoded hex in color:/backgroundColor:/borderColor:/tintColor: |
| ADVISORY | visual-system-font | custom fontFamily: |
| ADVISORY | system-status-bar | hardcoded StatusBar style="dark"/"light" |
| ADVISORY | motion-virtualized-lists | a file using both <ScrollView> and .map( |
Each finding links to expo-ios-hig/references/{rule}.md (path configurable in config.json) for the explanation and fix.
Setup
config.json is optional — sensible defaults apply. Override on first use if your project differs:
search_roots— space-separated source dirs to scan (defaultapp src components)skill_rules_dir— path used in report links to theexpo-ios-higrule files (default../expo-ios-hig/references)
If jq is installed, the script reads these from config.json; otherwise it uses the defaults. rg (ripgrep) is used when available, with a grep fallback — no hard dependency.
How to Use
1. Run scripts/verify-hig.sh against the Expo project root. 2. Read the grouped report; open the linked rule file for any finding to see the fix. 3. Treat ERRORS as must-fix before shipping; review ADVISORIES (they include intentional exceptions). 4. To extend: add a check ERROR|ADVISORY <rule> "<message>" "<regex>" line in run_checks() — see references/workflow.md.
Related Skills
- `expo-ios-hig` — the rules this verifier checks; every finding links back to it.
- `expo-ios-screen-scaffolder` — generates screens that pass these checks by construction.
{
"search_roots": "app src components",
"skill_rules_dir": "../expo-ios-hig/references",
"_setup_instructions": {
"search_roots": "Space-separated source directories to scan, relative to the project being checked (default: 'app src components'). If none exist, the whole project is scanned.",
"skill_rules_dir": "Path used in report links pointing to the expo-ios-hig rule files (default: '../expo-ios-hig/references'). Set to the location where the expo-ios-hig skill is installed so links resolve."
}
}
Gotchas
No known gotchas yet. Append entries here as failure points surface during real use, with dates.
Format:
### <short title>
<what goes wrong and how to avoid it>
Added: YYYY-MM-DD{
"version": "0.1.0",
"organization": "Expo iOS HIG",
"technology": "Expo (React Native) for iOS 26",
"discipline": "composition",
"type": "verification",
"date": "May 2026",
"abstract": "Read-only static verifier that scans an Expo (React Native) project for violations of the expo-ios-hig rules — Material component kits, JavaScript navigators instead of native stack/tabs, PanResponder, disabled font scaling, useNativeDriver:false, hardcoded hex colors, custom fonts, hardcoded status bar, and unvirtualized lists. Reports each finding with severity, file:line, and a link to the rule that explains the fix. Uses ripgrep when available with a grep fallback; safe to run unsupervised.",
"references": [
"https://developer.apple.com/design/human-interface-guidelines/",
"https://docs.expo.dev/router/advanced/stack/",
"https://reactnative.dev/docs/platformcolor",
"https://reactnative.dev/docs/accessibility"
]
}
Workflow: verifying an Expo iOS app against HIG
This document describes how scripts/verify-hig.sh works, how to read its output, and how to extend it.
Running
bash scripts/verify-hig.sh [project-dir] [--strict] [--json]project-dir— root of the Expo project to scan. Defaults to the current directory.--strict— exit non-zero on advisories as well as errors (use in CI to enforce everything).--json— emit findings as a JSON array (for tooling) instead of the text report.
The script is read-only. It opens no network connections and writes nothing to the target project.
How it works
1. Resolve search roots. From config.json (search_roots) or the default app src components. Roots that don't exist are skipped; if none exist, the whole project is scanned. 2. Pick a search tool. rg (ripgrep) if installed — faster and respects .gitignore — otherwise grep -rEn. Both restrict to .ts/.tsx/.js/.jsx and exclude node_modules. 3. Run checks. Each check is one call to check <severity> <rule> "<message>" "<regex>", which records a finding per matching line. The list/.map heuristic is a special check (check_scrollview_map). 4. Report. Findings are grouped into ERRORS then ADVISORIES, each with file:line and a link to expo-ios-hig/references/<rule>.md. 5. Exit. 0 if clean; 1 if any ERROR; with --strict, 1 if any advisory too.
Reading the output
ERRORS:
[native-avoid-material-ui] Material Design component kit imported on iOS
app/(trails)/new.tsx:3:import { FAB } from 'react-native-paper'
-> ../expo-ios-hig/references/native-avoid-material-ui.md- ERRORS are high-precision (import paths and literal flags). Treat them as must-fix before shipping.
- ADVISORIES are heuristics with possible false positives (a hex color in a theme file, a custom display font on a hero). Review each; some are intentional exceptions documented in the corresponding rule's "When NOT to use this pattern" section.
Fixing a finding
Open the linked rule file. Each expo-ios-hig rule has an Incorrect (the pattern this verifier flags) and a Correct example that is a minimal diff. Apply the correct form.
Extending the checks
Add a line inside run_checks() in scripts/verify-hig.sh:
check ERROR <rule-slug> "<human message>" "<extended-regex>"<rule-slug>must match a file underexpo-ios-hig/references/so the report link resolves.- Use
ERRORonly for high-precision patterns (imports, literal flags). UseADVISORYfor heuristics that may false-positive. - The regex is extended (ERE) and is passed to both
rg -eandgrep -E, so keep it portable (avoid PCRE-only constructs like lookaround).
For a multi-condition check (a file matching pattern A and pattern B), follow the shape of check_scrollview_map().
Limitations
- These are textual checks, not a type-aware AST analysis. They catch the common, high-signal patterns but cannot verify, for example, that every icon-only
Pressablehas anaccessibilityLabel(that needs an ESLint rule with JSX analysis). - Advisory heuristics will flag legitimate exceptions; that is by design — they prompt a look, not a guaranteed defect.
#!/usr/bin/env bash
# verify-hig.sh — Static HIG / native-feel checks for an Expo (React Native) iOS app.
# Part of: expo-ios-hig-verify
#
# Scans a project's source for patterns that violate the expo-ios-hig rules and
# prints a grouped report. Read-only: it never modifies the target project.
#
# Usage:
# verify-hig.sh [project-dir] [--strict] [--json]
# project-dir Directory to scan (default: current directory)
# --strict Exit non-zero on advisories too (default: only errors fail)
# --json Emit findings as a JSON array instead of the text report
#
# Exit codes: 0 = clean, 1 = violations found (or bad usage)
set -euo pipefail
SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
usage() {
cat >&2 <<'EOF'
Usage: verify-hig.sh [project-dir] [--strict] [--json]
project-dir Directory to scan (default: current directory)
--strict Exit non-zero on advisories as well as errors
--json Emit findings as a JSON array
EOF
}
# --- Parse arguments ---
TARGET="."
STRICT=0
JSON=0
while [[ $# -gt 0 ]]; do
case "$1" in
--strict) STRICT=1; shift ;;
--json) JSON=1; shift ;;
-h|--help) usage; exit 0 ;;
--*) echo "Error: unknown option '$1'." >&2; usage; exit 1 ;;
*) TARGET="$1"; shift ;;
esac
done
# --- Validate input ---
if [[ ! -d "$TARGET" ]]; then
echo "Error: '$TARGET' is not a directory." >&2
echo "Point verify-hig.sh at the root of your Expo project, e.g.: verify-hig.sh ./my-app" >&2
exit 1
fi
# --- Configuration (optional, via config.json + jq) ---
CONFIG="${SKILL_DIR}/config.json"
SEARCH_ROOTS="app src components"
RULES_LINK="../expo-ios-hig/references"
if command -v jq >/dev/null 2>&1 && [[ -f "$CONFIG" ]]; then
cfg_roots="$(jq -r '.search_roots // empty' "$CONFIG" 2>/dev/null || true)"
cfg_link="$(jq -r '.skill_rules_dir // empty' "$CONFIG" 2>/dev/null || true)"
[[ -n "$cfg_roots" ]] && SEARCH_ROOTS="$cfg_roots"
[[ -n "$cfg_link" ]] && RULES_LINK="$cfg_link"
fi
# --- Search helper (prefers ripgrep, falls back to grep) ---
do_search() {
# $1 = extended regex. Prints "path:line:content" for matching .ts/.tsx/.js/.jsx files.
local pattern="$1"
local -a roots=()
local r
for r in $SEARCH_ROOTS; do
[[ -d "$TARGET/$r" ]] && roots+=("$TARGET/$r")
done
[[ ${#roots[@]} -eq 0 ]] && roots=("$TARGET")
if command -v rg >/dev/null 2>&1; then
rg --no-heading --line-number --color never \
-g '*.ts' -g '*.tsx' -g '*.js' -g '*.jsx' -g '!node_modules' \
-e "$pattern" "${roots[@]}" 2>/dev/null || true
else
grep -rEn --include='*.ts' --include='*.tsx' --include='*.js' --include='*.jsx' \
--exclude-dir=node_modules -e "$pattern" "${roots[@]}" 2>/dev/null || true
fi
}
# --- Findings accumulation ---
ERRORS=0
ADVISORIES=0
declare -a FINDINGS=()
record() {
# $1 severity $2 rule $3 message $4 location
FINDINGS+=("$1"$'\t'"$2"$'\t'"$3"$'\t'"$4")
if [[ "$1" == "ERROR" ]]; then ERRORS=$((ERRORS + 1)); else ADVISORIES=$((ADVISORIES + 1)); fi
}
check() {
# $1 severity $2 rule $3 message $4 pattern
local severity="$1" rule="$2" message="$3" pattern="$4" matches line
matches="$(do_search "$pattern")"
[[ -z "$matches" ]] && return 0
while IFS= read -r line; do
[[ -z "$line" ]] && continue
record "$severity" "$rule" "$message" "$line"
done <<< "$matches"
}
check_scrollview_map() {
# Advisory: a file that uses <ScrollView> and .map( probably renders an unvirtualized list.
local files file loc
files="$(do_search '<ScrollView' | cut -d: -f1 | sort -u)"
[[ -z "$files" ]] && return 0
while IFS= read -r file; do
[[ -z "$file" ]] && continue
if grep -Eq '\.map\(' "$file" 2>/dev/null; then
loc="$(grep -En '<ScrollView' "$file" | head -1 | cut -d: -f1)"
record "ADVISORY" "motion-virtualized-lists" \
"ScrollView combined with .map() — use FlashList for long lists" "$file:$loc"
fi
done <<< "$files"
}
# --- Checks (ERROR = high precision, ADVISORY = heuristic) ---
run_checks() {
check ERROR native-avoid-material-ui "Material Design component kit imported on iOS" \
"from ['\"](react-native-paper|@react-native-material/|@rneui/|react-native-elements)"
check ERROR nav-native-stack "JavaScript stack navigator instead of the native stack" \
"(@react-navigation/stack|createStackNavigator)"
check ERROR touch-gesture-handler-thread "PanResponder runs gestures on the JS thread" \
"PanResponder"
check ERROR touch-pressable-feedback "TouchableWithoutFeedback gives no press feedback" \
"TouchableWithoutFeedback"
check ERROR acc-dynamic-type "allowFontScaling disabled — breaks Dynamic Type" \
"allowFontScaling(\s*=\s*\{\s*false\s*\}|\s*:\s*false)"
check ERROR motion-ui-thread-animation "useNativeDriver:false keeps the animation on the JS thread" \
"useNativeDriver\s*:\s*false"
check ADVISORY nav-native-tabs "createBottomTabNavigator is a JS tab bar — prefer native tabs" \
"createBottomTabNavigator"
check ADVISORY visual-semantic-colors "Hardcoded hex color — prefer PlatformColor semantic colors" \
"(color|backgroundColor|borderColor|tintColor)\s*:\s*['\"]#[0-9a-fA-F]{3,8}"
check ADVISORY visual-system-font "Custom fontFamily on interface text — prefer the system font" \
"fontFamily\s*:"
check ADVISORY system-status-bar "Hardcoded StatusBar style — prefer style=\"auto\"" \
"StatusBar[^\n]*style=['\"](dark|light)['\"]"
check_scrollview_map
}
# --- Output ---
print_text() {
echo "HIG verification report for: $TARGET"
echo "============================================================"
if [[ ${#FINDINGS[@]} -eq 0 ]]; then
echo "No HIG violations found."
echo "============================================================"
echo "Summary: 0 errors, 0 advisories"
return 0
fi
local sev label printed entry s rule msg loc
for sev in ERROR ADVISORY; do
printed=0
if [[ "$sev" == "ERROR" ]]; then label="ERRORS"; else label="ADVISORIES"; fi
for entry in "${FINDINGS[@]}"; do
IFS=$'\t' read -r s rule msg loc <<< "$entry"
[[ "$s" == "$sev" ]] || continue
if [[ $printed -eq 0 ]]; then echo ""; echo "$label:"; printed=1; fi
echo " [$rule] $msg"
echo " $loc"
echo " -> $RULES_LINK/$rule.md"
done
done
echo ""
echo "============================================================"
echo "Summary: $ERRORS errors, $ADVISORIES advisories"
}
json_escape() { printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'; }
print_json() {
local first=1 entry s rule msg loc
printf '['
if [[ ${#FINDINGS[@]} -gt 0 ]]; then
for entry in "${FINDINGS[@]}"; do
IFS=$'\t' read -r s rule msg loc <<< "$entry"
if [[ $first -eq 1 ]]; then first=0; else printf ','; fi
printf '{"severity":"%s","rule":"%s","message":"%s","location":"%s"}' \
"$s" "$rule" "$(json_escape "$msg")" "$(json_escape "$loc")"
done
fi
printf ']\n'
}
run_checks
if [[ $JSON -eq 1 ]]; then print_json; else print_text; fi
# --- Exit status ---
if [[ $ERRORS -gt 0 ]]; then exit 1; fi
if [[ $STRICT -eq 1 && $ADVISORIES -gt 0 ]]; then exit 1; fi
exit 0
Related skills
FAQ
What does expo-ios-hig-verify do?
expo-ios-hig-verify is a Claude Code skill for ai & agent building. It helps developers move faster with AI-assisted coding.
When should I use expo-ios-hig-verify?
When you need to helps with ai & agent building tasks during ai-assisted development, or when expo-ios-hig-verify is a claude code skill for ai & agent building. it helps developers move faster with ai-assisted coding.
What are the main capabilities?
expo-ios-hig-verify; AI & Agent Building; AI-coding skill.