React Native Styling & Layout
React Native doesn't use CSS files or the browser's layout engine. Styles are JavaScript objects with camelCased properties (backgroundColor, marginTop), and layout uses Flexbox implemented by the Yoga engine, which maps to native views on iOS and Android. If you know CSS Flexbox, most of it transfers, with a few important differences in defaults and units.
Mobile adds its own concerns: notches and home indicators (safe areas), wildly varying screen sizes and densities, platform conventions that differ between iOS and Android, users' font scaling preferences, and dark mode. This page covers styling fundamentals and the patterns and libraries teams use to keep styles consistent.
TL;DR
- Style with the
styleprop andStyleSheet.create. Values are unitless density-independent pixels (dp/pt). - Layout is Flexbox by default, with
flexDirection: 'column'as the default (unlike the web's row). - Use
flex: 1, percentages,gap, anduseWindowDimensionsfor responsive layouts. - Respect safe areas with
react-native-safe-area-context. - Handle platforms with
Platform.select/.ios.tsxand.android.tsxfiles, and themes withuseColorScheme. - Support font scaling (accessibility), and consider NativeWind (Tailwind), Tamagui, Unistyles, or a design token system for consistency.
Quick Example
Core Concepts
Styles as Objects
- The
styleprop accepts an object, aStyleSheetreference, or an array (later entries override earlier ones, and falsy values are ignored), which is handy for conditional styles. StyleSheet.createvalidates styles in development, and communicates intent. Performance benefits are small with the New Architecture, but it keeps code organized.- There's no cascade: styles don't inherit, except text styles nested inside
<Text>elements. Wrap reusable styling in components instead.
Units
Numbers are density-independent pixels (points on iOS, dp on Android): width: 100 looks the same physical size across screen densities. Percentages work for dimensions and positions (width: '50%'). There are no em, rem, or vh units. Use useWindowDimensions() for screen-relative sizing, and PixelRatio for pixel-precise work (hairlines: StyleSheet.hairlineWidth).
Flexbox With Yoga
React Native layouts are Flexbox, with differences from the web:
gap, rowGap, and columnGap are supported. Every View is a flex container, and there's no display: block, grid, or floats. position: 'absolute' works relative to the parent. See CSS Flexbox for the core model.
Responsive Layouts
- Use
flex, percentages,maxWidth, andaspectRatiorather than fixed pixel widths. useWindowDimensions()updates on rotation and window resizing (iPad multitasking, foldables, and Android desktop windowing).- Adapt layouts for tablets (multi-column lists, split views) with breakpoints based on width.
Safe Areas
Notches, Dynamic Island, rounded corners, status bars, and home indicators obscure parts of the screen. react-native-safe-area-context provides SafeAreaView (with configurable edges) and useSafeAreaInsets() for precise padding. Navigation libraries integrate with it, and Android's edge-to-edge display is now the norm, so insets matter on both platforms.
Platform Differences
Platform.OSandPlatform.select({ ios, android, default }).- Platform-specific files:
Button.ios.tsxandButton.android.tsxare resolved automatically. - Shadows: iOS uses
shadow*properties, Android useselevation. Newer versions support the cross-platformboxShadowstyle andfilterunder the New Architecture. - Respect platform conventions (navigation patterns, typography, haptics) rather than making both platforms look identical.
Dark Mode and Theming
useColorScheme() returns 'light', 'dark', or null, and updates when the system theme changes. Build a theme object (colors, spacing, typography tokens) provided via context, or use a styling library with theming support. Set status bar style accordingly. See dark mode theming and design tokens.
Typography and Font Scaling
Users can increase system font size, and <Text> respects it by default (allowFontScaling). Design layouts that grow with larger text (avoid fixed heights on text containers), cap extreme scaling with maxFontSizeMultiplier only where necessary, and test with accessibility sizes. Custom fonts load via Expo Font or native linking. See accessibility.
Styling Libraries
Best Practices
Centralize Design Tokens
Define colors, spacing, radii, and typography once (a theme object or library tokens), and use them everywhere. It makes dark mode and rebranding simple, and keeps UI consistent.
Build Primitives
Create Box, Text, Button, Card, and Screen components that apply tokens, safe areas, and accessibility defaults. Screens then compose primitives rather than repeating raw styles.
Test on Real Devices and Sizes
Check small phones, large phones, tablets, both platforms, landscape orientation, dark mode, and large font sizes. Simulators miss performance and some rendering differences.
Keep Touch Targets Large
Pressable elements should be at least about 44×44 pt (iOS) or 48×48 dp (Android). Use hitSlop to extend small icons' touch areas.
Common Mistakes
Forgetting flex: 1 on Containers
A screen whose root View lacks flex: 1 (or a height) collapses to its content, so scroll views and backgrounds don't fill the screen.
Hard-Coding Status Bar Heights
Assuming a 20pt or 44pt status bar breaks on notched devices, Dynamic Island, Android cutouts, and edge-to-edge layouts. Use safe area insets.
Fixed-Height Text Containers
Buttons and list rows with fixed heights clip text when users enable larger fonts. Let content define height, with padding and minimum heights.
FAQ
Does React Native use CSS?
No. It uses JavaScript style objects with CSS-like property names in camelCase, and a subset of CSS behavior. Layout is Flexbox via Yoga. Libraries like NativeWind let you write Tailwind classes that compile to React Native styles.
Why is the default flex direction column?
Mobile screens are typically laid out vertically, so React Native defaults flexDirection to column. Set flexDirection: 'row' for horizontal arrangements.
How do I handle the notch and home indicator?
Use react-native-safe-area-context: wrap screens in SafeAreaView (choosing which edges to pad), or apply useSafeAreaInsets() values as padding. Navigation libraries typically handle headers and tab bars for you.
How do I implement dark mode in React Native?
Read the system preference with useColorScheme(), select colors from light and dark theme objects (usually via context or a styling library), and update the status bar style. Test all screens in both modes, including images and third-party components.
Related Topics
- React Native — The framework overview
- CSS Flexbox — The layout model React Native uses
- React Native Performance — Rendering efficiency
- Dark Mode Theming — Designing dark themes
- Responsive Design — Adapting to screen sizes
- Tailwind — Utility styling via NativeWind