Flexbox layout and responsive design

The flexbox defaults that differ from CSS, sizing with flex and percentages, safe areas and notches, orientation changes, tablets and dark mode.

Flexbox defaults that surprise web developers

import { View, Text, StyleSheet } from 'react-native';

export function Row() {
  return (
    <View style={styles.container}>
      <View style={styles.avatar} />
      <View style={styles.body}>
        <Text numberOfLines={1} style={styles.title}>A long headline that should truncate</Text>
        <Text style={styles.subtitle}>Secondary line</Text>
      </View>
      <View style={styles.badge} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flexDirection: 'row', alignItems: 'center', padding: 12, gap: 12 },
  avatar: { width: 44, height: 44, borderRadius: 22, backgroundColor: '#c7d2fe' },
  body: { flex: 1, minWidth: 0 },        // minWidth 0 lets the text shrink and truncate
  title: { fontSize: 16, fontWeight: '600' },
  subtitle: { color: '#6b7280' },
  badge: { paddingHorizontal: 8, paddingVertical: 2, borderRadius: 8, backgroundColor: '#e5e7eb' },
});
  • flexDirection defaults to column, the opposite of the CSS default.
  • flexShrink defaults to 1 in React Native, and flex: 1 means grow, shrink and basis zero.
  • A Text inside a row needs minWidth: 0 or its parent to shrink before it will truncate.
  • There is no cascade and no inheritance except from Text to nested Text. Every style is explicit.

Dimensions, safe areas and tablets

import { useWindowDimensions } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

export function useLayout() {
  const { width, height, fontScale } = useWindowDimensions();
  const insets = useSafeAreaInsets();

  const isTablet = Math.min(width, height) >= 600;
  const isLandscape = width > height;
  const columns = width >= 900 ? 3 : width >= 600 ? 2 : 1;
  const gutter = isTablet ? 24 : 16;

  return { width, height, fontScale, insets, isTablet, isLandscape, columns, gutter };
}

export function Screen({ children }: { children: React.ReactNode }) {
  const { insets, gutter } = useLayout();
  return (
    <View style={{ flex: 1, paddingTop: insets.top, paddingHorizontal: gutter }}>
      {children}
    </View>
  );
}
ConcernAPINote
Notch and home indicatoruseSafeAreaInsetsWrap the app in SafeAreaProvider once
Orientation changeuseWindowDimensionsRe-renders on change; Dimensions.get does not
Tablet splitWidth breakpointsDo not branch on Platform.isPad alone
Text scaleallowFontScalingLeave it on; test at 200 percent

Read dimensions from the hook rather than the static Dimensions module. The hook subscribes to changes, so a rotation updates the layout without any manual listener.

Dark mode and platform differences

import { useColorScheme, Platform, StyleSheet, Text, View } from 'react-native';

export function Card({ title }: { title: string }) {
  const scheme = useColorScheme();
  const isDark = scheme === 'dark';

  return (
    <View style={[styles.card, { backgroundColor: isDark ? '#1f2937' : '#ffffff' }]}>
      <Text style={{ color: isDark ? '#f9fafb' : '#111827' }}>{title}</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  card: {
    borderRadius: 12,
    padding: 16,
    ...Platform.select({
      ios: { shadowColor: '#000', shadowOpacity: 0.12, shadowRadius: 8, shadowOffset: { width: 0, height: 2 } },
      android: { elevation: 2 },
      default: {},
    }),
  },
});
💡
Android elevation and iOS shadow properties are not interchangeable. Shadow on iOS is painted by the layer; on Android it is a real elevation that also affects z-order, and it is ignored entirely on a view with a transparent background.

FAQ

How do I make a layout work on a phone and a tablet?
Use width breakpoints from useWindowDimensions and express the layout as a number of columns or a pane split. Avoid separate components per device — one adaptive layout is far less code to maintain.
Why is my text truncated at a strange point?
The parent cannot shrink below its intrinsic width. Add minWidth: 0 to the flex parent, or flexShrink: 1 to the text container, then set numberOfLines and ellipsizeMode.

Lists, forms and input handling Modern JavaScript and TypeScript for React Native

Last refreshed 2026-09-18.