reactnative
/

React Native Styling – StyleSheet, Flexbox, Theming & Performance

Last Sync: Today

On this page

9
0%
5 min read
Remaining
5 minleft

Click any section to jump — progress syncs automatically

reactnative

React Native Styling – StyleSheet, Flexbox, Theming & Performance

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.

  1. 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.

React JSXRead-only
1
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>
  );
}

  1. 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.

React JSXRead-only
1
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+)

  1. 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.

React JSXRead-only
1
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;

  1. 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.

React TSXRead-only
1
// 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>
  );
};

  1. 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.

React JSXRead-only
1
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} />
);

  1. 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.

React JSXRead-only
1
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>
);

  1. Advanced Styling Techniques

Master advanced styling patterns: shadows, gradients, absolute positioning, transforms, and custom fonts.

React JSXRead-only
1
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;

  1. Performance Optimization for Styles

Optimize styling performance to avoid jank and unnecessary re-renders. Follow these best practices for production apps.

React JSXRead-only
1
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;

Test Your Knowledge

Q1
of 4

What is the default flexDirection in React Native?

A
row
B
column
C
row-reverse
D
column-reverse
Q2
of 4

Which method is recommended for creating static styles?

A
StyleSheet.create
B
inline styles
C
CSS modules
D
styled-components
Q3
of 4

How do you detect the system color scheme preference?

A
useTheme()
B
useColorScheme()
C
useAppearance()
D
useDarkMode()
Q4
of 4

Which property creates spacing inside a component?

A
margin
B
padding
C
border
D
gap

Frequently Asked Questions

Should I use StyleSheet.create or inline styles?

Always use StyleSheet.create for static styles. It validates styles at compile time, creates optimized native style objects (sent once to native side), and improves performance. Use inline styles only for dynamic values that change frequently based on state or props.

How do I handle different screen sizes responsively?

Use useWindowDimensions() hook to get screen dimensions, implement scaling functions (scaleWidth, scaleHeight, moderateScale), use percentage-based widths, and adjust layouts based on screen width (e.g., isTablet, isSmallDevice). Avoid hardcoded pixel values.

What's the difference between padding and margin in React Native?

Same as CSS: padding is space inside the component (between content and border), margin is space outside the component (between components). However, margin collapsing doesn't occur in React Native like in web CSS.

How do I implement dark mode in React Native?

Use useColorScheme() to detect system preference, create a theme provider with Context API, define light/dark theme objects, and use the theme values in your styles. Avoid hardcoding colors. Support 'light', 'dark', and 'system' modes.

Previous

react native components

Next

react native layout

Related Content

Need help?

Explore our comprehensive docs or start a chat with our tech experts.