React Native Styling – From Basics to Advanced
React Native uses a CSS-like styling system that's actually JavaScript objects. Styles are applied using the style prop, with StyleSheet.create being the recommended approach for performance. In 2026, the styling ecosystem includes built-in solutions for dark mode, dynamic theming, and platform-specific adaptations. This guide covers everything from Flexbox fundamentals to production-ready theming systems.
- Styling Methods – StyleSheet vs Inline Styles
React Native offers three primary styling methods. StyleSheet.create is the most performant and recommended for static styles. Inline styles are useful for dynamic values but should be used sparingly.
import React from 'react'; import { View, Text, StyleSheet, TouchableOpacity } from 'react-native'; // METHOD 1: StyleSheet.create (RECOMMENDED for static styles) const styles = StyleSheet.create({ container: { flex: 1, padding: 20, backgroundColor: '#fff' }, title: { fontSize: 24, fontWeight: 'bold', color: '#333', marginBottom: 10 }, button: { backgroundColor: '#007AFF', paddingVertical: 12, paddingHorizontal: 24, borderRadius: 8, alignItems: 'center' }, buttonText: { color: '#fff', fontSize: 16, fontWeight: '600' } }); // METHOD 2: Inline styles (for dynamic values only) const DynamicStyleExample = ({ isActive }) => ( <View style={{ backgroundColor: isActive ? '#4CD964' : '#FF3B30', padding: 10, borderRadius: 8, opacity: isActive ? 1 : 0.6 }}> <Text style={{ color: '#fff' }}> {isActive ? 'Active' : 'Inactive'} </Text> </View> ); // METHOD 3: Array of styles (for composition) const ComposedStylesExample = () => ( <View style={[styles.container, { backgroundColor: '#f5f5f5' }]}> <Text style={[styles.title, { color: '#007AFF' }]}> Composed Title </Text> <TouchableOpacity style={[styles.button, { backgroundColor: '#34C759' }]}> <Text style={styles.buttonText}>Custom Button</Text> </TouchableOpacity> </View> ); // Performance Best Practices const PerformanceExample = () => { // BAD: Creating style objects on each render // <View style={{ padding: 10, margin: 5 }} /> // GOOD: Use StyleSheet.create or memoized styles return <View style={styles.container} />; }; export default function StylingMethodsDemo() { return ( <View style={styles.container}> <Text style={styles.title}>StyleSheet Example</Text> <TouchableOpacity style={styles.button}> <Text style={styles.buttonText}>Button</Text> </TouchableOpacity> <DynamicStyleExample isActive={true} /> <ComposedStylesExample /> </View> ); }
- Flexbox Layout System
React Native uses a subset of CSS Flexbox. The key difference: flexDirection defaults to column (not row like web). Understanding Flexbox is essential for creating responsive layouts.
import React from 'react'; import { View, Text, StyleSheet, ScrollView } from 'react-native'; const FlexboxExamples = () => { return ( <ScrollView style={styles.wrapper}> <Text style={styles.sectionTitle}>1. Basic Flex Direction</Text> <View style={styles.rowContainer}> <View style={[styles.box, { backgroundColor: '#FF3B30' }]}><Text>1</Text></View> <View style={[styles.box, { backgroundColor: '#FF9500' }]}><Text>2</Text></View> <View style={[styles.box, { backgroundColor: '#FFCC00' }]}><Text>3</Text></View> </View> <Text style={styles.sectionTitle}>2. Column (Default)</Text> <View style={styles.columnContainer}> <View style={[styles.box, { backgroundColor: '#4CD964' }]}><Text>1</Text></View> <View style={[styles.box, { backgroundColor: '#007AFF' }]}><Text>2</Text></View> <View style={[styles.box, { backgroundColor: '#5856D6' }]}><Text>3</Text></View> </View> <Text style={styles.sectionTitle}>3. Justify Content</Text> <View style={styles.justifySpaceBetween}> <View style={[styles.smallBox, { backgroundColor: '#FF3B30' }]} /> <View style={[styles.smallBox, { backgroundColor: '#FF9500' }]} /> <View style={[styles.smallBox, { backgroundColor: '#FFCC00' }]} /> </View> <Text style={styles.sectionTitle}>4. Align Items</Text> <View style={styles.alignCenter}> <View style={[styles.variableBox, { height: 40, backgroundColor: '#4CD964' }]} /> <View style={[styles.variableBox, { height: 60, backgroundColor: '#007AFF' }]} /> <View style={[styles.variableBox, { height: 80, backgroundColor: '#5856D6' }]} /> </View> <Text style={styles.sectionTitle}>5. Flex Wrap</Text> <View style={styles.flexWrapContainer}> {[...Array(10)].map((_, i) => ( <View key={i} style={[styles.wrapBox, { backgroundColor: '#34C759' }]}> <Text style={styles.wrapText}>{i + 1}</Text> </View> ))} </View> <Text style={styles.sectionTitle}>6. Flex Grow / Shrink</Text> <View style={styles.flexGrowContainer}> <View style={[styles.fixedBox, { backgroundColor: '#FF3B30' }]}> <Text>Fixed</Text> </View> <View style={[styles.growBox, { backgroundColor: '#007AFF' }]}> <Text>Grows</Text> </View> <View style={[styles.fixedBox, { backgroundColor: '#5856D6' }]}> <Text>Fixed</Text> </View> </View> <Text style={styles.sectionTitle}>7. Absolute Positioning</Text> <View style={styles.relativeContainer}> <View style={styles.absoluteBox}> <Text style={{ color: '#fff' }}>Absolute</Text> </View> <Text>Background Content</Text> </View> </ScrollView> ); }; const styles = StyleSheet.create({ wrapper: { flex: 1, padding: 16, backgroundColor: '#fff' }, sectionTitle: { fontSize: 18, fontWeight: 'bold', marginTop: 20, marginBottom: 12 }, // Row container rowContainer: { flexDirection: 'row', justifyContent: 'space-around', backgroundColor: '#f0f0f0', padding: 10, borderRadius: 8 }, // Column container columnContainer: { flexDirection: 'column', alignItems: 'center', backgroundColor: '#f0f0f0', padding: 10, borderRadius: 8, gap: 10 }, box: { width: 60, height: 60, justifyContent: 'center', alignItems: 'center', borderRadius: 8 }, smallBox: { width: 50, height: 50, borderRadius: 8 }, variableBox: { width: 100, borderRadius: 8, marginVertical: 5 }, // Justify Content: space-between justifySpaceBetween: { flexDirection: 'row', justifyContent: 'space-between', backgroundColor: '#f0f0f0', padding: 10, borderRadius: 8 }, // Align Items: center alignCenter: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-around', backgroundColor: '#f0f0f0', padding: 10, borderRadius: 8, height: 120 }, // Flex Wrap flexWrapContainer: { flexDirection: 'row', flexWrap: 'wrap', gap: 8, backgroundColor: '#f0f0f0', padding: 10, borderRadius: 8 }, wrapBox: { width: 60, height: 60, justifyContent: 'center', alignItems: 'center', borderRadius: 8 }, wrapText: { color: '#fff', fontWeight: 'bold' }, // Flex Grow / Shrink flexGrowContainer: { flexDirection: 'row', backgroundColor: '#f0f0f0', padding: 10, borderRadius: 8, height: 80, alignItems: 'center', gap: 10 }, fixedBox: { width: 70, height: 50, justifyContent: 'center', alignItems: 'center', borderRadius: 8 }, growBox: { flex: 1, height: 50, justifyContent: 'center', alignItems: 'center', borderRadius: 8 }, // Absolute Positioning relativeContainer: { height: 150, backgroundColor: '#f0f0f0', borderRadius: 8, justifyContent: 'center', alignItems: 'center', position: 'relative' }, absoluteBox: { position: 'absolute', top: 10, right: 10, backgroundColor: '#FF3B30', padding: 8, borderRadius: 8, zIndex: 1 } }); export default FlexboxExamples; // Flexbox Properties Reference: // flexDirection: 'row' | 'column' | 'row-reverse' | 'column-reverse' (default: 'column') // justifyContent: 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly' // alignItems: 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline' // alignSelf: 'auto' | 'flex-start' | 'flex-end' | 'center' | 'stretch' // flexWrap: 'wrap' | 'nowrap' | 'wrap-reverse' // flex: number (0 = no grow, 1+ = distribute remaining space) // flexGrow: number (how much to grow relative to siblings) // flexShrink: number (how much to shrink relative to siblings) // flexBasis: number | 'auto' (initial size before growing/shrinking) // gap: number (spacing between children, iOS 13+, Android 10+)
- Dynamic & Conditional Styling
Style values often depend on component state, props, or user interactions. Use computed styles and the array syntax for clean conditional styling.
import React, { useState } from 'react'; import { View, Text, TouchableOpacity, StyleSheet, TextInput, ScrollView } from 'react-native'; const DynamicStylingExamples = () => { const [isPressed, setIsPressed] = useState(false); const [inputValue, setInputValue] = useState(''); const [selectedTab, setSelectedTab] = useState(0); const [progress, setProgress] = useState(0.5); // Conditional styles based on state const buttonStyles = [ styles.button, isPressed && styles.buttonPressed ]; // Dynamic computed styles const progressBarStyle = { width: `${progress * 100}%`, height: 8, backgroundColor: '#007AFF', borderRadius: 4 }; // Style based on props/state const getTabStyle = (index) => [ styles.tab, selectedTab === index && styles.activeTab ]; const getTabTextStyle = (index) => [ styles.tabText, selectedTab === index && styles.activeTabText ]; // Dynamic color based on input length const getInputBorderColor = () => { if (inputValue.length === 0) return '#ccc'; if (inputValue.length < 5) return '#FF9500'; return '#4CD964'; }; return ( <ScrollView style={styles.container}> <Text style={styles.title}>Dynamic & Conditional Styling</Text> {/* Conditional styling with array */} <TouchableOpacity style={buttonStyles} onPressIn={() => setIsPressed(true)} onPressOut={() => setIsPressed(false)} activeOpacity={1} > <Text style={styles.buttonText}> {isPressed ? 'Pressed!' : 'Press Me'} </Text> </TouchableOpacity> {/* Dynamic computed styles */} <View style={styles.progressContainer}> <View style={styles.progressBackground}> <View style={progressBarStyle} /> </View> <View style={styles.progressControls}> <TouchableOpacity style={styles.smallButton} onPress={() => setProgress(Math.max(0, progress - 0.1))} > <Text>-</Text> </TouchableOpacity> <Text>{Math.round(progress * 100)}%</Text> <TouchableOpacity style={styles.smallButton} onPress={() => setProgress(Math.min(1, progress + 0.1))} > <Text>+</Text> </TouchableOpacity> </View> </View> {/* Dynamic border color based on validation */} <TextInput style={[ styles.input, { borderColor: getInputBorderColor(), borderWidth: 2 } ]} placeholder="Enter text (min 5 chars)" value={inputValue} onChangeText={setInputValue} /> {inputValue.length > 0 && inputValue.length < 5 && ( <Text style={styles.warningText}>Minimum 5 characters required</Text> )} {/* Tab bar with dynamic active styles */} <View style={styles.tabBar}> {['Tab 1', 'Tab 2', 'Tab 3'].map((tab, index) => ( <TouchableOpacity key={index} style={getTabStyle(index)} onPress={() => setSelectedTab(index)} > <Text style={getTabTextStyle(index)}>{tab}</Text> </TouchableOpacity> ))} </View> {/* Opacity based on state */} <View style={[styles.card, { opacity: selectedTab === 0 ? 1 : 0.5 }]}> <Text>Content for {selectedTab === 0 ? 'Tab 1' : 'Other Tab'}</Text> </View> {/* Transform animations */} <TouchableOpacity style={styles.transformButton} onPress={() => {}} activeOpacity={0.8} > <Text style={styles.buttonText}>Transform Button</Text> </TouchableOpacity> </ScrollView> ); }; const styles = StyleSheet.create({ container: { flex: 1, padding: 16, backgroundColor: '#fff' }, title: { fontSize: 24, fontWeight: 'bold', marginBottom: 20 }, button: { backgroundColor: '#007AFF', padding: 16, borderRadius: 12, alignItems: 'center', marginBottom: 20, transform: [{ scale: 1 }] }, buttonPressed: { backgroundColor: '#0055CC', transform: [{ scale: 0.98 }] }, buttonText: { color: '#fff', fontSize: 16, fontWeight: '600' }, progressContainer: { marginBottom: 20 }, progressBackground: { backgroundColor: '#e0e0e0', borderRadius: 4, overflow: 'hidden' }, progressControls: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center', gap: 20, marginTop: 10 }, smallButton: { backgroundColor: '#f0f0f0', paddingHorizontal: 20, paddingVertical: 8, borderRadius: 8 }, input: { borderWidth: 2, borderRadius: 8, padding: 12, fontSize: 16, marginBottom: 8 }, warningText: { color: '#FF9500', fontSize: 12, marginBottom: 20 }, tabBar: { flexDirection: 'row', backgroundColor: '#f0f0f0', borderRadius: 12, padding: 4, marginBottom: 20 }, tab: { flex: 1, paddingVertical: 12, alignItems: 'center', borderRadius: 8 }, activeTab: { backgroundColor: '#007AFF' }, tabText: { fontSize: 14, color: '#666' }, activeTabText: { color: '#fff', fontWeight: '600' }, card: { backgroundColor: '#f9f9f9', padding: 20, borderRadius: 12, alignItems: 'center', marginBottom: 20 }, transformButton: { backgroundColor: '#34C759', padding: 16, borderRadius: 12, alignItems: 'center', transform: [{ rotate: '0deg' }] } }); export default DynamicStylingExamples;
- Theming & Dark Mode
Implement a robust theming system using React Context. Support both light and dark modes, and allow dynamic switching. Use useColorScheme for system preference detection.
// src/shared/theme/ThemeProvider.tsx import React, { createContext, useContext, useState, useEffect } from 'react'; import { useColorScheme, Appearance } from 'react-native'; // Define theme colors export const lightTheme = { colors: { primary: '#007AFF', primaryDark: '#0055CC', secondary: '#5856D6', success: '#34C759', warning: '#FF9500', danger: '#FF3B30', background: '#FFFFFF', surface: '#F8F9FA', card: '#FFFFFF', text: '#000000', textSecondary: '#6C757D', border: '#E9ECEF', divider: '#E9ECEF', shadow: '#000000', statusBar: 'dark-content' }, spacing: { xs: 4, sm: 8, md: 16, lg: 24, xl: 32, xxl: 48 }, typography: { h1: { fontSize: 32, fontWeight: 'bold' }, h2: { fontSize: 24, fontWeight: 'bold' }, h3: { fontSize: 20, fontWeight: '600' }, body: { fontSize: 16, fontWeight: 'normal' }, caption: { fontSize: 12, fontWeight: 'normal' } }, borderRadius: { sm: 4, md: 8, lg: 12, xl: 16, round: 999 } }; export const darkTheme = { colors: { primary: '#0A84FF', primaryDark: '#0055CC', secondary: '#5E5CE6', success: '#30D158', warning: '#FF9F0A', danger: '#FF453A', background: '#000000', surface: '#1C1C1E', card: '#1C1C1E', text: '#FFFFFF', textSecondary: '#8E8E93', border: '#38383A', divider: '#38383A', shadow: '#000000', statusBar: 'light-content' }, spacing: lightTheme.spacing, typography: lightTheme.typography, borderRadius: lightTheme.borderRadius }; type Theme = typeof lightTheme; type ThemeMode = 'light' | 'dark' | 'system'; interface ThemeContextType { theme: Theme; mode: ThemeMode; setMode: (mode: ThemeMode) => void; isDark: boolean; } const ThemeContext = createContext<ThemeContextType | undefined>(undefined); export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const systemColorScheme = useColorScheme(); const [mode, setMode] = useState<ThemeMode>('system'); const [theme, setTheme] = useState<Theme>(lightTheme); useEffect(() => { const effectiveMode = mode === 'system' ? systemColorScheme || 'light' : mode; setTheme(effectiveMode === 'dark' ? darkTheme : lightTheme); }, [mode, systemColorScheme]); const isDark = mode === 'dark' || (mode === 'system' && systemColorScheme === 'dark'); return ( <ThemeContext.Provider value={{ theme, mode, setMode, isDark }}> {children} </ThemeContext.Provider> ); }; export const useTheme = () => { const context = useContext(ThemeContext); if (!context) { throw new Error('useTheme must be used within ThemeProvider'); } return context; }; // Usage in components // src/shared/components/ThemedButton.tsx import React from 'react'; import { TouchableOpacity, Text, StyleSheet } from 'react-native'; import { useTheme } from '../theme/ThemeProvider'; interface ThemedButtonProps { title: string; onPress: () => void; variant?: 'primary' | 'secondary' | 'danger'; } export const ThemedButton: React.FC<ThemedButtonProps> = ({ title, onPress, variant = 'primary' }) => { const { theme } = useTheme(); const getBackgroundColor = () => { switch (variant) { case 'primary': return theme.colors.primary; case 'secondary': return theme.colors.secondary; case 'danger': return theme.colors.danger; default: return theme.colors.primary; } }; return ( <TouchableOpacity style={[styles.button, { backgroundColor: getBackgroundColor() }]} onPress={onPress} > <Text style={[styles.text, { color: theme.colors.text }]}>{title}</Text> </TouchableOpacity> ); }; const styles = StyleSheet.create({ button: { paddingVertical: 12, paddingHorizontal: 24, borderRadius: 8, alignItems: 'center' }, text: { fontSize: 16, fontWeight: '600' } }); // App.tsx – Wrap with ThemeProvider import { ThemeProvider } from './src/shared/theme/ThemeProvider'; export default function App() { return ( <ThemeProvider> <MainApp /> </ThemeProvider> ); } // Theme toggle component const ThemeToggle: React.FC = () => { const { mode, setMode, isDark } = useTheme(); return ( <View style={styles.container}> <TouchableOpacity style={[styles.option, mode === 'light' && styles.active]} onPress={() => setMode('light')} > <Text>Light</Text> </TouchableOpacity> <TouchableOpacity style={[styles.option, mode === 'dark' && styles.active]} onPress={() => setMode('dark')} > <Text>Dark</Text> </TouchableOpacity> <TouchableOpacity style={[styles.option, mode === 'system' && styles.active]} onPress={() => setMode('system')} > <Text>System</Text> </TouchableOpacity> </View> ); };
- Platform-Specific Styling
Handle iOS and Android differences with Platform.select(), platform-specific file extensions, or the Platform module. This ensures native look and feel on each platform.
import React from 'react'; import { View, Text, StyleSheet, Platform, TouchableOpacity, SafeAreaView, StatusBar } from 'react-native'; const PlatformSpecificStyling = () => { // Method 1: Platform.select for styles const styles = StyleSheet.create({ container: { flex: 1, padding: Platform.select({ ios: 20, android: 16, default: 12 // Other platforms (web, windows, macos) }), backgroundColor: '#fff' }, header: { paddingTop: Platform.OS === 'ios' ? 44 : StatusBar.currentHeight, paddingBottom: 12, backgroundColor: Platform.select({ ios: '#f8f8f8', android: '#6200EE' }), ...Platform.select({ ios: { shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1 }, android: { elevation: 4 } }) }, button: { paddingVertical: 12, paddingHorizontal: 24, borderRadius: Platform.OS === 'ios' ? 8 : 4, ...Platform.select({ ios: { backgroundColor: '#007AFF', }, android: { backgroundColor: '#6200EE', elevation: 2 } }) }, buttonText: { color: '#fff', fontSize: 16, fontWeight: '600', ...Platform.select({ ios: { fontFamily: 'System', }, android: { fontFamily: 'Roboto', textTransform: 'uppercase' } }) }, card: { backgroundColor: '#fff', borderRadius: Platform.OS === 'ios' ? 12 : 4, padding: 16, marginVertical: 8, ...Platform.select({ ios: { shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4 }, android: { elevation: 2 } }) } }); // Method 2: Inline Platform.select const getButtonStyle = () => ({ backgroundColor: Platform.OS === 'ios' ? '#007AFF' : '#6200EE', paddingVertical: Platform.OS === 'ios' ? 12 : 10, borderRadius: Platform.OS === 'ios' ? 8 : 4 }); // Method 3: Platform-specific component const renderDatePicker = () => { if (Platform.OS === 'ios') { return <IOSTimePicker />; } else { return <AndroidTimePicker />; } }; // Method 4: Platform version checks const isIos15OrHigher = Platform.OS === 'ios' && parseInt(Platform.Version as string, 10) >= 15; const isAndroid12OrHigher = Platform.OS === 'android' && Platform.Version >= 31; return ( <SafeAreaView style={styles.container}> <View style={styles.header}> <Text style={{ fontSize: 20, fontWeight: 'bold', color: '#fff' }}> Platform: {Platform.OS} </Text> <Text style={{ fontSize: 12, color: '#fff', opacity: 0.8 }}> Version: {Platform.Version} </Text> </View> <View style={{ padding: 16 }}> <View style={styles.card}> <Text style={{ fontSize: 16, fontWeight: 'bold', marginBottom: 8 }}> Platform Specific Card </Text> <Text> This card uses {Platform.OS === 'ios' ? 'shadow' : 'elevation'} for depth. </Text> </View> <TouchableOpacity style={styles.button}> <Text style={styles.buttonText}> {Platform.OS === 'ios' ? 'iOS Button' : 'Android Button'} </Text> </TouchableOpacity> <View style={styles.card}> <Text style={{ fontWeight: 'bold', marginBottom: 8 }}>Platform Details:</Text> <Text>• OS: {Platform.OS}</Text> <Text>• Version: {Platform.Version}</Text> <Text>• isTV: {Platform.isTV ? 'Yes' : 'No'}</Text> {Platform.OS === 'android' && ( <Text>• API Level: {Platform.constants?.apiLevel}</Text> )} {Platform.OS === 'ios' && ( <Text>• iOS 15+: {isIos15OrHigher ? 'Yes' : 'No'}</Text> )} </View> <View style={styles.card}> <Text style={{ fontWeight: 'bold', marginBottom: 8 }}>Platform.select Examples:</Text> <Text>• Padding: {Platform.select({ ios: 20, android: 16 })}</Text> <Text>• Ripple: {Platform.select({ ios: 'No ripple', android: 'Ripple effect' })}</Text> <Text>• Haptic: {Platform.select({ ios: 'UIImpactFeedback', android: 'Vibration' })}</Text> </View> </View> </SafeAreaView> ); }; // Dummy components for demonstration const IOSTimePicker = () => <Text>iOS Date Picker</Text>; const AndroidTimePicker = () => <Text>Android Date Picker</Text>; export default PlatformSpecificStyling; // Platform-specific file extensions (alternative approach): // Button.ios.tsx – iOS specific implementation // Button.android.tsx – Android specific implementation // Then import: import Button from './Button'; // Example: Button.ios.tsx export const Button = (props) => ( <TouchableOpacity style={styles.iosButton} {...props} /> ); // Example: Button.android.tsx export const Button = (props) => ( <TouchableOpacity style={styles.androidButton} {...props} /> );
- Responsive Design & Screen Sizes
Create responsive layouts that work across different screen sizes (iPhone SE to iPad Pro). Use Dimensions, percentage-based widths, and responsive scaling functions.
import React from 'react'; import { View, Text, StyleSheet, Dimensions, ScrollView, useWindowDimensions } from 'react-native'; // Method 1: Using Dimensions API const { width: screenWidth, height: screenHeight } = Dimensions.get('window'); // Responsive scaling functions const guidelineBaseWidth = 375; // iPhone 12/13/14 const guidelineBaseHeight = 812; // Scale width proportionally const scaleWidth = (size: number) => (screenWidth / guidelineBaseWidth) * size; // Scale height proportionally const scaleHeight = (size: number) => (screenHeight / guidelineBaseHeight) * size; // Moderate scaling (with limits) const moderateScale = (size: number, factor = 0.5) => size + (scaleWidth(size) - size) * factor; // Method 2: Using useWindowDimensions hook (reacts to orientation changes) const ResponsiveDesignExample = () => { const { width, height, scale, fontScale } = useWindowDimensions(); const isLandscape = width > height; const isTablet = width >= 768; const isSmallDevice = width <= 375; // Responsive grid columns const numColumns = isTablet ? 4 : isLandscape ? 3 : 2; const itemWidth = (width - (numColumns + 1) * 12) / numColumns; return ( <ScrollView style={styles.container}> <Text style={styles.title}>Responsive Design</Text> {/* Device info card */} <View style={styles.infoCard}> <Text>Screen Width: {Math.round(width)}px</Text> <Text>Screen Height: {Math.round(height)}px</Text> <Text>Scale: {scale}</Text> <Text>Font Scale: {fontScale}</Text> <Text>Orientation: {isLandscape ? 'Landscape' : 'Portrait'}</Text> <Text>Device: {isTablet ? 'Tablet' : 'Phone'}</Text> </View> {/* Responsive grid */} <Text style={styles.subtitle}>Responsive Grid ({numColumns} columns)</Text> <View style={styles.gridContainer}> {[...Array(6)].map((_, i) => ( <View key={i} style={[ styles.gridItem, { width: itemWidth, height: itemWidth } ]} > <Text style={styles.gridText}>Item {i + 1}</Text> </View> ))} </View> {/* Responsive text */} <Text style={styles.subtitle}>Responsive Typography</Text> <Text style={[styles.responsiveText, { fontSize: moderateScale(16), padding: moderateScale(12) }]}> This text scales with device size. On larger screens, it's proportionally larger. </Text> {/* Conditional layouts based on screen size */} {isTablet ? ( <View style={styles.twoColumnLayout}> <View style={styles.column}> <Text>Column 1 (Tablet Layout)</Text> </View> <View style={styles.column}> <Text>Column 2 (Tablet Layout)</Text> </View> </View> ) : ( <View style={styles.singleColumnLayout}> <Text>Single Column (Phone Layout)</Text> </View> )} {/* Percentage-based widths */} <View style={styles.percentageContainer}> <View style={[styles.percentageBox, { width: '25%', backgroundColor: '#FF3B30' }]}> <Text style={styles.percentageText}>25%</Text> </View> <View style={[styles.percentageBox, { width: '50%', backgroundColor: '#007AFF' }]}> <Text style={styles.percentageText}>50%</Text> </View> <View style={[styles.percentageBox, { width: '25%', backgroundColor: '#34C759' }]}> <Text style={styles.percentageText}>25%</Text> </View> </View> </ScrollView> ); }; const styles = StyleSheet.create({ container: { flex: 1, padding: 16, backgroundColor: '#fff' }, title: { fontSize: 24, fontWeight: 'bold', marginBottom: 16 }, subtitle: { fontSize: 18, fontWeight: '600', marginTop: 20, marginBottom: 12 }, infoCard: { backgroundColor: '#f0f0f0', padding: 16, borderRadius: 12, gap: 4 }, gridContainer: { flexDirection: 'row', flexWrap: 'wrap', gap: 12 }, gridItem: { backgroundColor: '#007AFF', borderRadius: 8, justifyContent: 'center', alignItems: 'center' }, gridText: { color: '#fff', fontWeight: '600' }, responsiveText: { backgroundColor: '#f5f5f5', borderRadius: 8, lineHeight: 24 }, twoColumnLayout: { flexDirection: 'row', gap: 16, marginTop: 12 }, column: { flex: 1, backgroundColor: '#e0e0e0', padding: 20, borderRadius: 8, alignItems: 'center' }, singleColumnLayout: { backgroundColor: '#e0e0e0', padding: 20, borderRadius: 8, alignItems: 'center', marginTop: 12 }, percentageContainer: { flexDirection: 'row', marginTop: 12, height: 60 }, percentageBox: { justifyContent: 'center', alignItems: 'center' }, percentageText: { color: '#fff', fontWeight: 'bold' } }); export default ResponsiveDesignExample; // Safe area insets for notches and dynamic island import { SafeAreaView } from 'react-native-safe-area-context'; // Use SafeAreaView for modern devices const SafeAreaExample = () => ( <SafeAreaView style={{ flex: 1, backgroundColor: '#fff' }}> {/* Content will avoid notches and home indicator */} </SafeAreaView> );
- Advanced Styling Techniques
Master advanced styling patterns: shadows, gradients, absolute positioning, transforms, and custom fonts.
import React from 'react'; import { View, Text, StyleSheet, TouchableOpacity, ScrollView, Image, Platform } from 'react-native'; import LinearGradient from 'react-native-linear-gradient'; const AdvancedStylingExamples = () => { return ( <ScrollView style={styles.container}> <Text style={styles.title}>Advanced Styling Techniques</Text> {/* 1. Shadows (cross-platform) */} <Text style={styles.subtitle}>1. Shadow Effects</Text> <View style={styles.shadowContainer}> <View style={[styles.card, styles.shadowLight]}> <Text>Light Shadow</Text> </View> <View style={[styles.card, styles.shadowMedium]}> <Text>Medium Shadow</Text> </View> <View style={[styles.card, styles.shadowHeavy]}> <Text>Heavy Shadow</Text> </View> </View> {/* 2. Gradients */} <Text style={styles.subtitle}>2. Linear Gradients</Text> <LinearGradient colors={['#FF3B30', '#FF9500', '#FFCC00']} start={{ x: 0, y: 0 }} end={{ x: 1, y: 1 }} style={styles.gradient} > <Text style={styles.gradientText}>Linear Gradient</Text> </LinearGradient> <LinearGradient colors={['#4CD964', '#007AFF', '#5856D6']} start={{ x: 0, y: 0 }} end={{ x: 0, y: 1 }} style={styles.gradientVertical} > <Text style={styles.gradientText}>Vertical Gradient</Text> </LinearGradient> {/* 3. Transforms */} <Text style={styles.subtitle}>3. Transformations</Text> <View style={styles.transformContainer}> <View style={[styles.transformBox, styles.transformRotate]}> <Text>Rotate</Text> </View> <View style={[styles.transformBox, styles.transformScale]}> <Text>Scale</Text> </View> <View style={[styles.transformBox, styles.transformSkew]}> <Text>Skew</Text> </View> <View style={[styles.transformBox, styles.transformTranslate]}> <Text>Translate</Text> </View> </View> {/* 4. Border Radius Variations */} <Text style={styles.subtitle}>4. Border Radius</Text> <View style={styles.borderContainer}> <View style={[styles.borderBox, styles.borderRounded]}> <Text>Rounded</Text> </View> <View style={[styles.borderBox, styles.borderCircle]}> <Text>Circle</Text> </View> <View style={[styles.borderBox, styles.borderPill]}> <Text>Pill</Text> </View> <View style={[styles.borderBox, styles.borderCorners]}> <Text>Custom</Text> </View> </View> {/* 5. Custom Fonts (requires linking) */} <Text style={styles.subtitle}>5. Custom Fonts</Text> <Text style={styles.customFont}>Custom Font Example</Text> {/* 6. Blur View (iOS only) */} {Platform.OS === 'ios' && ( <> <Text style={styles.subtitle}>6. Blur Effect (iOS)</Text> <View style={styles.blurContainer}> <Image source={{ uri: 'https://picsum.photos/300/200' }} style={styles.blurImage} /> <View style={styles.blurOverlay}> <Text style={styles.blurText}>Blurred Overlay</Text> </View> </View> </> )} {/* 7. Overlay & Opacity */} <Text style={styles.subtitle}>7. Overlays</Text> <View style={styles.overlayContainer}> <Image source={{ uri: 'https://picsum.photos/300/150' }} style={styles.overlayImage} /> <View style={styles.darkOverlay}> <Text style={styles.overlayText}>Dark Overlay</Text> </View> </View> {/* 8. Neumorphism */} <Text style={styles.subtitle}>8. Neumorphism</Text> <View style={styles.neumorphContainer}> <View style={styles.neumorphBox} /> </View> </ScrollView> ); }; const styles = StyleSheet.create({ container: { flex: 1, padding: 16, backgroundColor: '#f5f5f5' }, title: { fontSize: 24, fontWeight: 'bold', marginBottom: 20 }, subtitle: { fontSize: 18, fontWeight: '600', marginTop: 20, marginBottom: 12 }, // Shadows shadowContainer: { flexDirection: 'row', justifyContent: 'space-around', flexWrap: 'wrap', gap: 12 }, card: { backgroundColor: '#fff', padding: 20, borderRadius: 12, minWidth: 100, alignItems: 'center' }, shadowLight: { ...Platform.select({ ios: { shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4 }, android: { elevation: 2 } }) }, shadowMedium: { ...Platform.select({ ios: { shadowColor: '#000', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.2, shadowRadius: 6 }, android: { elevation: 4 } }) }, shadowHeavy: { ...Platform.select({ ios: { shadowColor: '#000', shadowOffset: { width: 0, height: 8 }, shadowOpacity: 0.3, shadowRadius: 12 }, android: { elevation: 8 } }) }, // Gradients gradient: { padding: 20, borderRadius: 12, marginBottom: 12 }, gradientVertical: { padding: 20, borderRadius: 12, marginBottom: 12 }, gradientText: { color: '#fff', fontSize: 18, fontWeight: 'bold', textAlign: 'center' }, // Transforms transformContainer: { flexDirection: 'row', flexWrap: 'wrap', gap: 12 }, transformBox: { width: 80, height: 80, backgroundColor: '#007AFF', justifyContent: 'center', alignItems: 'center', borderRadius: 8 }, transformRotate: { transform: [{ rotate: '15deg' }] }, transformScale: { transform: [{ scale: 0.9 }] }, transformSkew: { transform: [{ skewX: '-15deg' }] }, transformTranslate: { transform: [{ translateX: 10 }, { translateY: 5 }] }, // Border Radius borderContainer: { flexDirection: 'row', flexWrap: 'wrap', gap: 12 }, borderBox: { width: 80, height: 80, backgroundColor: '#34C759', justifyContent: 'center', alignItems: 'center' }, borderRounded: { borderRadius: 12 }, borderCircle: { borderRadius: 40 }, borderPill: { borderRadius: 40, width: 120 }, borderCorners: { borderTopLeftRadius: 20, borderTopRightRadius: 8, borderBottomLeftRadius: 8, borderBottomRightRadius: 20 }, // Custom Fonts customFont: { fontFamily: Platform.OS === 'ios' ? 'Helvetica Neue' : 'Roboto', fontSize: 18, fontWeight: 'bold' }, // Blur (iOS) blurContainer: { position: 'relative', height: 150, borderRadius: 12, overflow: 'hidden' }, blurImage: { width: '100%', height: '100%' }, blurOverlay: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, backgroundColor: 'rgba(255,255,255,0.7)', justifyContent: 'center', alignItems: 'center' }, blurText: { fontSize: 18, fontWeight: 'bold' }, // Overlays overlayContainer: { position: 'relative', height: 150, borderRadius: 12, overflow: 'hidden' }, overlayImage: { width: '100%', height: '100%' }, darkOverlay: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'center', alignItems: 'center' }, overlayText: { color: '#fff', fontSize: 18, fontWeight: 'bold' }, // Neumorphism neumorphContainer: { alignItems: 'center', padding: 20 }, neumorphBox: { width: 120, height: 120, borderRadius: 60, backgroundColor: '#e0e0e0', ...Platform.select({ ios: { shadowColor: '#fff', shadowOffset: { width: -5, height: -5 }, shadowOpacity: 0.5, shadowRadius: 10 } }) } }); export default AdvancedStylingExamples;
- Performance Optimization for Styles
Optimize styling performance to avoid jank and unnecessary re-renders. Follow these best practices for production apps.
import React, { useMemo, memo } from 'react'; import { View, Text, StyleSheet, FlatList, TouchableOpacity } from 'react-native'; // PERFORMANCE TIPS: // 1. ALWAYS use StyleSheet.create for static styles // BAD: <View style={{ padding: 10, margin: 5 }} /> // GOOD: <View style={styles.container} /> // 2. Memoize dynamic styles const DynamicComponent = ({ isActive }) => { // BAD: Creating new style object on each render // const containerStyle = { backgroundColor: isActive ? 'blue' : 'gray' }; // GOOD: Memoize computed styles const containerStyle = useMemo(() => ({ backgroundColor: isActive ? '#007AFF' : '#e0e0e0', padding: 16, borderRadius: 8 }), [isActive]); return <View style={containerStyle} />; }; // 3. Use StyleSheet.compose for merging styles const composedStyle = StyleSheet.compose(styles.base, styles.active); // 4. Avoid inline functions in style props // BAD: <TouchableOpacity onPress={() => {}} style={{ ... }} /> // GOOD: Define handler outside render // 5. Use React.memo for components with complex styles const OptimizedListItem = memo(({ item, onPress }) => { return ( <TouchableOpacity onPress={onPress} style={styles.listItem}> <Text style={styles.listItemText}>{item.title}</Text> </TouchableOpacity> ); }); // 6. Use FlatList's getItemLayout for fixed height items const getItemLayout = (data, index) => ({ length: 70, // Item height offset: 70 * index, index }); // 7. Avoid unnecessary nesting (flatten view hierarchy) // BAD: <View><View><View><Text /></View></View></View> // GOOD: Reduce nesting depth // 8. Use removeClippedSubviews for FlatList // <FlatList removeClippedSubviews={true} /> // 9. Optimize images with proper dimensions // <Image source={...} style={{ width: 100, height: 100 }} /> // 10. Use shouldComponentUpdate or React.memo const styles = StyleSheet.create({ container: { flex: 1, padding: 16 }, base: { padding: 10, borderRadius: 5 }, active: { backgroundColor: '#007AFF' }, listItem: { height: 70, padding: 12, borderBottomWidth: 1, borderBottomColor: '#e0e0e0' }, listItemText: { fontSize: 16 } }); // Performance monitoring import { PerformanceObserver } from 'react-native-performance'; const measureRenderTime = (componentName) => { const start = performance.now(); return () => { const end = performance.now(); if (end - start > 16) { // 60fps threshold console.warn(`${componentName} render took ${end - start}ms`); } }; }; // Usage const MyComponent = () => { const endMeasure = measureRenderTime('MyComponent'); // Component logic endMeasure(); return <View />; }; export default PerformanceOptimization;