Skip to main content
useWindowDimensions is a React hook that returns the current dimensions of the application window. It automatically updates when the window is resized, making it ideal for creating responsive layouts.

Signature

function useWindowDimensions(): {
  width: number;
  height: number;
  scale: number;
  fontScale: number;
}

Returns

An object containing:
  • width - The width of the window in density-independent pixels (dp)
  • height - The height of the window in density-independent pixels (dp)
  • scale - The pixel density of the device (e.g., 2 for @2x, 3 for @3x)
  • fontScale - The font scale factor set by the user’s accessibility settings
Android only:
  • densityDpi - The screen density expressed as dots-per-inch

Usage

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

function ResponsiveComponent() {
  const { width, height, scale, fontScale } = useWindowDimensions();

  return (
    <View>
      <Text>Window Width: {width}</Text>
      <Text>Window Height: {height}</Text>
      <Text>Pixel Density: {scale}x</Text>
      <Text>Font Scale: {fontScale}</Text>
    </View>
  );
}

Common Patterns

Responsive Layout

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

function ResponsiveLayout() {
  const { width } = useWindowDimensions();

  // Switch between mobile and tablet layouts
  const isTablet = width >= 768;

  return (
    <View style={isTablet ? styles.tabletContainer : styles.mobileContainer}>
      {/* Your content */}
    </View>
  );
}

const styles = StyleSheet.create({
  mobileContainer: {
    flexDirection: 'column',
    padding: 16,
  },
  tabletContainer: {
    flexDirection: 'row',
    padding: 24,
  },
});

Dynamic Grid Columns

import { useWindowDimensions, FlatList, View } from 'react-native';

function GridView({ data }: { data: any[] }) {
  const { width } = useWindowDimensions();

  // Calculate number of columns based on width
  const getNumColumns = () => {
    if (width >= 1024) return 4;
    if (width >= 768) return 3;
    if (width >= 480) return 2;
    return 1;
  };

  const numColumns = getNumColumns();
  const itemWidth = width / numColumns - 16;

  return (
    <FlatList
      data={data}
      numColumns={numColumns}
      key={numColumns} // Force re-render on column change
      renderItem={({ item }) => (
        <View style={{ width: itemWidth, margin: 8 }}>
          {/* Item content */}
        </View>
      )}
    />
  );
}

Orientation-Aware Layout

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

function OrientationAware() {
  const { width, height } = useWindowDimensions();

  const isPortrait = height > width;
  const isLandscape = width > height;

  return (
    <View>
      <Text>Orientation: {isPortrait ? 'Portrait' : 'Landscape'}</Text>
      <View
        style={{
          flexDirection: isPortrait ? 'column' : 'row',
        }}
      >
        {/* Layout that adapts to orientation */}
      </View>
    </View>
  );
}

Accessibility-Aware Typography

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

function AccessibleText() {
  const { fontScale } = useWindowDimensions();

  // Adjust layout based on user's font size preferences
  const baseFontSize = 16;
  const scaledFontSize = baseFontSize * fontScale;

  return (
    <Text style={[styles.text, { fontSize: baseFontSize }]}>
      This text respects system font scaling ({fontScale.toFixed(2)}x)
    </Text>
  );
}

const styles = StyleSheet.create({
  text: {
    // fontSize will be scaled by the system automatically
    // but you can use fontScale for layout adjustments
  },
});

Responsive Image Sizing

import { useWindowDimensions, Image, View } from 'react-native';

function ResponsiveImage({ source }: { source: any }) {
  const { width, scale } = useWindowDimensions();

  // Calculate optimal image size
  const imageWidth = Math.min(width * 0.9, 600);
  const imageHeight = imageWidth * 0.75; // 4:3 aspect ratio

  // Use scale to load appropriate resolution
  const shouldLoadHighRes = scale >= 2;

  return (
    <View style={{ alignItems: 'center' }}>
      <Image
        source={source}
        style={{ width: imageWidth, height: imageHeight }}
        resizeMode="cover"
      />
    </View>
  );
}
import { useWindowDimensions, View, Modal, StyleSheet } from 'react-native';

function CenteredModal({ visible, children }: { visible: boolean; children: React.ReactNode }) {
  const { width, height } = useWindowDimensions();

  const modalWidth = Math.min(width * 0.9, 500);
  const modalHeight = Math.min(height * 0.8, 600);

  return (
    <Modal visible={visible} transparent>
      <View style={styles.backdrop}>
        <View
          style={[
            styles.modalContent,
            {
              width: modalWidth,
              height: modalHeight,
            },
          ]}
        >
          {children}
        </View>
      </View>
    </Modal>
  );
}

const styles = StyleSheet.create({
  backdrop: {
    flex: 1,
    backgroundColor: 'rgba(0, 0, 0, 0.5)',
    justifyContent: 'center',
    alignItems: 'center',
  },
  modalContent: {
    backgroundColor: 'white',
    borderRadius: 12,
    padding: 20,
  },
});

Dimensions vs useWindowDimensions

useWindowDimensions is preferred over the Dimensions API for components because:
  • Automatic updates: The hook automatically re-renders your component when dimensions change
  • React lifecycle: Properly integrates with React’s component lifecycle
  • No manual cleanup: Subscriptions are managed automatically
// ❌ Old way - requires manual subscription management
import { Dimensions, useEffect, useState } from 'react-native';

function OldWay() {
  const [dimensions, setDimensions] = useState(Dimensions.get('window'));

  useEffect(() => {
    const subscription = Dimensions.addEventListener('change', ({ window }) => {
      setDimensions(window);
    });
    return () => subscription.remove();
  }, []);

  return <View style={{ width: dimensions.width }} />;
}

// ✅ New way - hook handles everything
function NewWay() {
  const { width } = useWindowDimensions();
  return <View style={{ width }} />;
}

Implementation Details

This hook:
  • Uses useState to store current dimensions
  • Subscribes to dimension changes in a useEffect
  • Handles missed updates between initial render and subscription
  • Filters out no-op updates when dimensions haven’t actually changed
  • Automatically cleans up subscriptions on unmount

Platform Differences

iOS

Returns width, height, scale, and fontScale.

Android

Returns width, height, scale, fontScale, and densityDpi.

Window vs Screen

This hook returns window dimensions (the visible app area), not screen dimensions. On Android with split-screen, this reflects only your app’s window.

Performance Considerations

  • The hook efficiently prevents unnecessary re-renders by comparing dimension values
  • Only updates state when dimensions actually change
  • Subscription cleanup is automatic and efficient

See Also

Build docs developers (and LLMs) love