# React Native Styling Patterns ## StyleSheet Fundamentals ### Creating Styles ```typescript import { StyleSheet, ViewStyle, TextStyle, ImageStyle } from "react-native"; // Typed styles for better IDE support interface Styles { container: ViewStyle; title: TextStyle; image: ImageStyle; } const styles = StyleSheet.create({ container: { flex: 1, padding: 16, backgroundColor: "#ffffff", }, title: { fontSize: 24, fontWeight: "700", color: "#1f2937", }, image: { width: 100, height: 100, borderRadius: 8, }, }); ``` ### Combining Styles ```typescript import { StyleProp, ViewStyle } from 'react-native'; interface BoxProps { style?: StyleProp; variant?: 'default' | 'primary' | 'danger'; } function Box({ style, variant = 'default' }: BoxProps) { return ( ); } const styles = StyleSheet.create({ base: { padding: 16, borderRadius: 8, backgroundColor: '#f3f4f6', }, primary: { backgroundColor: '#6366f1', }, danger: { backgroundColor: '#ef4444', }, }); ``` ## Theme System ### Theme Context ```typescript import React, { createContext, useContext, useMemo } from 'react'; import { useColorScheme } from 'react-native'; interface Theme { colors: { primary: string; secondary: string; background: string; surface: string; text: string; textSecondary: string; border: string; error: string; success: string; }; spacing: { xs: number; sm: number; md: number; lg: number; xl: number; }; borderRadius: { sm: number; md: number; lg: number; full: number; }; typography: { h1: { fontSize: number; fontWeight: string; lineHeight: number }; h2: { fontSize: number; fontWeight: string; lineHeight: number }; body: { fontSize: number; fontWeight: string; lineHeight: number }; caption: { fontSize: number; fontWeight: string; lineHeight: number }; }; } const lightTheme: Theme = { colors: { primary: '#6366f1', secondary: '#8b5cf6', background: '#ffffff', surface: '#f9fafb', text: '#1f2937', textSecondary: '#6b7280', border: '#e5e7eb', error: '#ef4444', success: '#10b981', }, spacing: { xs: 4, sm: 8, md: 16, lg: 24, xl: 32, }, borderRadius: { sm: 4, md: 8, lg: 16, full: 9999, }, typography: { h1: { fontSize: 32, fontWeight: '700', lineHeight: 40 }, h2: { fontSize: 24, fontWeight: '600', lineHeight: 32 }, body: { fontSize: 16, fontWeight: '400', lineHeight: 24 }, caption: { fontSize: 12, fontWeight: '400', lineHeight: 16 }, }, }; const darkTheme: Theme = { ...lightTheme, colors: { primary: '#818cf8', secondary: '#a78bfa', background: '#111827', surface: '#1f2937', text: '#f9fafb', textSecondary: '#9ca3af', border: '#374151', error: '#f87171', success: '#34d399', }, }; const ThemeContext = createContext(lightTheme); export function ThemeProvider({ children }: { children: React.ReactNode }) { const colorScheme = useColorScheme(); const theme = useMemo( () => (colorScheme === 'dark' ? darkTheme : lightTheme), [colorScheme] ); return ( {children} ); } export function useTheme() { return useContext(ThemeContext); } ``` ### Using Theme ```typescript import { useTheme } from './theme'; function ThemedCard() { const theme = useTheme(); return ( Card Title Card description text ); } ``` ## Responsive Design ### Screen Dimensions ```typescript import { Dimensions, useWindowDimensions, PixelRatio } from 'react-native'; // Get dimensions once (may be stale after rotation) const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window'); // Responsive scaling const guidelineBaseWidth = 375; const guidelineBaseHeight = 812; export const scale = (size: number) => (SCREEN_WIDTH / guidelineBaseWidth) * size; export const verticalScale = (size: number) => (SCREEN_HEIGHT / guidelineBaseHeight) * size; export const moderateScale = (size: number, factor = 0.5) => size + (scale(size) - size) * factor; // Hook for dynamic dimensions (handles rotation) function ResponsiveComponent() { const { width, height } = useWindowDimensions(); const isLandscape = width > height; const isTablet = width >= 768; return ( {/* Content */} ); } ``` ### Breakpoint System ```typescript import { useWindowDimensions } from 'react-native'; type Breakpoint = 'sm' | 'md' | 'lg' | 'xl'; const breakpoints = { sm: 0, md: 768, lg: 1024, xl: 1280, }; export function useBreakpoint(): Breakpoint { const { width } = useWindowDimensions(); if (width >= breakpoints.xl) return 'xl'; if (width >= breakpoints.lg) return 'lg'; if (width >= breakpoints.md) return 'md'; return 'sm'; } export function useResponsiveValue(values: Partial>): T | undefined { const breakpoint = useBreakpoint(); const breakpointOrder: Breakpoint[] = ['xl', 'lg', 'md', 'sm']; const currentIndex = breakpointOrder.indexOf(breakpoint); for (let i = currentIndex; i < breakpointOrder.length; i++) { const bp = breakpointOrder[i]; if (values[bp] !== undefined) { return values[bp]; } } return undefined; } // Usage function ResponsiveGrid() { const columns = useResponsiveValue({ sm: 1, md: 2, lg: 3, xl: 4 }) ?? 1; return ( {items.map((item) => ( ))} ); } ``` ## Layout Components ### Container ```typescript import { View, ViewStyle, StyleProp } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { useTheme } from './theme'; interface ContainerProps { children: React.ReactNode; style?: StyleProp; edges?: ('top' | 'bottom' | 'left' | 'right')[]; } export function Container({ children, style, edges = ['top', 'bottom'] }: ContainerProps) { const insets = useSafeAreaInsets(); const theme = useTheme(); return ( {children} ); } ``` ### Stack Components ```typescript import { View, ViewStyle, StyleProp } from 'react-native'; interface StackProps { children: React.ReactNode; spacing?: number; style?: StyleProp; } export function VStack({ children, spacing = 8, style }: StackProps) { return ( {children} ); } export function HStack({ children, spacing = 8, style }: StackProps) { return ( {children} ); } // Usage function Example() { return ( John Doe john@example.com