Mobile Native Standards Enforcer
This skill ensures all code adheres to the mobile native template's core principles. Apply these checks proactively when creating or modifying components, screens, or any UI code.
Before Making Changes
Run this validation checklist mentally or explicitly:
Standards Validation:
- [ ] No hardcoded colors (hex codes or Tailwind color classes)
- [ ] Using theme system via useTheme() hook
- [ ] Safe areas handled with useSafeAreaInsets() or layout components
- [ ] Platform-specific code uses correct patterns
- [ ] TypeScript strict mode compliant (no 'any' types)
- [ ] Animations use Reanimated 4
- [ ] Component is production-grade (if creating new component)
Core Principle Enforcement
1. Zero Hardcoded Colors
Rule: Every color must come from the theme system.
Check for violations:
- Hex codes:
#000000, #FFFFFF, #FF5733, etc.
- RGB/RGBA values:
rgb(0,0,0), rgba(255,255,255,0.5)
- Tailwind color classes:
bg-black, text-blue-500, border-red-600
- Named colors:
backgroundColor: 'red', color: 'white'
Correct pattern:
typescript
1import { useTheme } from '@/hooks';
2
3const { colors } = useTheme();
4
5// For View/TouchableOpacity/Pressable
6<View style={{ backgroundColor: colors.background.primary }} />
7
8// For Text
9<Text style={{ color: colors.text.primary }} />
10
11// For borders
12<View style={{ borderColor: colors.border.default }} />
Available theme colors (check constants/colors.ts for complete list):
colors.background.* - primary, secondary, tertiary, elevated
colors.text.* - primary, secondary, tertiary, inverse
colors.border.* - default, subtle, emphasis
colors.surface.* - primary, secondary, overlay
colors.accent.* - primary, secondary, success, warning, error, info
If you see a violation: Stop and refactor to use theme colors before proceeding.
2. Safe Area Handling
Rule: Never use deprecated SafeAreaView from react-native.
Check for violations:
typescript
1// ❌ WRONG - deprecated
2import { SafeAreaView } from 'react-native';
Correct patterns:
Option A: Use the hook (preferred for animations)
typescript
1import { useSafeAreaInsets } from 'react-native-safe-area-context';
2
3const insets = useSafeAreaInsets();
4
5<View style={{ paddingTop: insets.top, paddingBottom: insets.bottom }}>
6 {/* content */}
7</View>
Option B: Use layout components
typescript
1import { ScreenLayout } from '@/components/layouts';
2
3<ScreenLayout>
4 {/* content - safe areas handled automatically */}
5</ScreenLayout>
Rule: Use correct patterns for platform differences.
For full component differences, use file extensions:
Component.ios.tsx // iOS 26 Liquid Glass implementation
Component.android.tsx // Android 16 Material 3 implementation
Component.web.tsx // Web fallback
Component.tsx // Base/shared logic or type exports
For minor differences, use Platform module:
typescript
1import { Platform } from 'react-native';
2
3const hitSlop = Platform.select({
4 ios: { top: 10, bottom: 10, left: 10, right: 10 },
5 android: 20,
6 default: 10
7});
8
9// Or conditional logic
10if (Platform.OS === 'ios') {
11 // iOS-specific code
12} else if (Platform.OS === 'android') {
13 // Android-specific code
14}
4. Animation Standards
Rule: All animations must use Reanimated 4.
Check for violations:
- Using
Animated from react-native (deprecated)
- Using
LayoutAnimation (unreliable)
- CSS transitions on web that don't work on native
Correct pattern:
typescript
1import Animated, {
2 FadeIn,
3 FadeOut,
4 SlideInRight,
5 useAnimatedStyle,
6 withTiming
7} from 'react-native-reanimated';
8
9// Entering/exiting animations
10<Animated.View entering={FadeIn} exiting={FadeOut}>
11 {/* content */}
12</Animated.View>
13
14// Custom animations
15const animatedStyle = useAnimatedStyle(() => ({
16 opacity: withTiming(isVisible ? 1 : 0)
17}));
5. TypeScript Strict Mode
Rule: No any types. Use proper generics and type inference.
Check for violations:
typescript
1// ❌ WRONG
2const data: any = fetchData();
3function process(item: any) { }
Correct patterns:
typescript
1// ✅ Use proper types
2interface User {
3 id: string;
4 name: string;
5}
6
7const data: User[] = fetchData();
8
9// ✅ Use generics
10function process<T>(item: T): T {
11 return item;
12}
13
14// ✅ Use unknown for truly unknown types, then narrow
15const data: unknown = fetchData();
16if (typeof data === 'object' && data !== null) {
17 // Now you can safely access properties
18}
Production-Grade Component Standards
When creating a new component in components/ui/, it must meet ALL criteria:
Component Checklist
Production Component Requirements:
- [ ] Fully typed with TypeScript strict mode
- [ ] Props interface exported and documented with JSDoc
- [ ] Supports light/dark mode via useTheme()
- [ ] Has variants (size, color, state) as needed
- [ ] Works on iOS, Android, and web
- [ ] Uses Reanimated 4 for animations
- [ ] Handles accessibility (accessibilityLabel, accessibilityRole)
- [ ] No hardcoded colors or spacing
- [ ] Uses centralized spacing from constants/spacing.ts
- [ ] Exported from components/ui/index.ts
Component Template
Use this structure for new components:
typescript
1import React from 'react';
2import { View, Text, Pressable } from 'react-native';
3import { useTheme } from '@/hooks';
4import { spacing } from '@/constants';
5
6/**
7 * [Component description]
8 *
9 * @example
10 * ```tsx
11 * <YourComponent variant="primary" size="medium">
12 * Content
13 * </YourComponent>
14 * ```
15 */
16
17interface YourComponentProps {
18 /** Component children */
19 children?: React.ReactNode;
20 /** Visual variant */
21 variant?: 'primary' | 'secondary' | 'tertiary';
22 /** Size variant */
23 size?: 'small' | 'medium' | 'large';
24 /** Optional callback */
25 onPress?: () => void;
26}
27
28export function YourComponent({
29 children,
30 variant = 'primary',
31 size = 'medium',
32 onPress,
33}: YourComponentProps) {
34 const { colors } = useTheme();
35
36 // Calculate styles based on props
37 const backgroundColor = variant === 'primary'
38 ? colors.accent.primary
39 : colors.background.secondary;
40
41 const paddingSize = size === 'small'
42 ? spacing.sm
43 : size === 'large'
44 ? spacing.lg
45 : spacing.md;
46
47 return (
48 <Pressable
49 onPress={onPress}
50 style={{
51 backgroundColor,
52 padding: paddingSize,
53 borderRadius: spacing.xs,
54 }}
55 accessibilityRole="button"
56 >
57 <Text style={{ color: colors.text.primary }}>
58 {children}
59 </Text>
60 </Pressable>
61 );
62}
Common Violations and Fixes
Violation: Hardcoded Black Background
typescript
1// ❌ WRONG
2<View style={{ backgroundColor: '#000000' }} />
3<View className="bg-black" />
4
5// ✅ CORRECT
6const { colors } = useTheme();
7<View style={{ backgroundColor: colors.background.primary }} />
Violation: Using SafeAreaView from React Native
typescript
1// ❌ WRONG
2import { SafeAreaView } from 'react-native';
3
4<SafeAreaView>
5 <View>Content</View>
6</SafeAreaView>
7
8// ✅ CORRECT
9import { useSafeAreaInsets } from 'react-native-safe-area-context';
10
11const insets = useSafeAreaInsets();
12
13<View style={{ paddingTop: insets.top }}>
14 <View>Content</View>
15</View>
Violation: Any Type Usage
typescript
1// ❌ WRONG
2function handleData(data: any) {
3 console.log(data.name);
4}
5
6// ✅ CORRECT
7interface Data {
8 name: string;
9}
10
11function handleData(data: Data) {
12 console.log(data.name);
13}
Violation: Magic Numbers for Spacing
typescript
1// ❌ WRONG
2<View style={{ padding: 16, margin: 8 }} />
3
4// ✅ CORRECT
5import { spacing } from '@/constants';
6
7<View style={{ padding: spacing.md, margin: spacing.sm }} />
Violation: Using Animated from react-native
typescript
1// ❌ WRONG
2import { Animated } from 'react-native';
3
4const fadeAnim = new Animated.Value(0);
5
6// ✅ CORRECT
7import Animated, { FadeIn } from 'react-native-reanimated';
8
9<Animated.View entering={FadeIn}>
10 {/* content */}
11</Animated.View>
Enforcement Workflow
When creating or modifying code:
- Before writing: Review relevant standards above
- While writing: Use theme system, proper imports, and types
- After writing: Run the validation checklist
- If violations found: Fix immediately before proceeding
Quick Reference
Colors: const { colors } = useTheme();
Safe Areas: const insets = useSafeAreaInsets();
Spacing: import { spacing } from '@/constants';
Platform: import { Platform } from 'react-native';
Animation: import Animated, { FadeIn } from 'react-native-reanimated';
Philosophy Reminder
This template prioritizes:
- Native first: iOS 26 Liquid Glass + Android 16 Material 3 Expressive
- No shortcuts: Three platform implementations if needed
- Design system discipline: Single source of truth for all styles
Enforce these principles in every change.