skip to content

In React Native 0.87, why is core SafeAreaView deprecated, and how do you keep a chat screen clear of the notch using react-native-safe-area-context?

level: juniorimportance: must knowfreq 58%

answer

  1. one platform, padding only
  2. Android draws behind the bars now
  3. a provider at the root
  4. pick edges, default all four
  5. hook returns four numbers

basics

~10 s

Core SafeAreaView is iOS-only, applies padding only and does not work with Android edge-to-edge, so 0.81 deprecated it. Use react-native-safe-area-context: SafeAreaProvider at the root, its SafeAreaView with edges, or useSafeAreaInsets for explicit padding.

solid answer

~40 s

React Native's own `SafeAreaView` was built as limited iOS support: it only pads, it ignores padding you set on it, and it does nothing for Android. Android 15 draws apps that target API 35 edge to edge, and Android 16, React Native's default target since 0.81, has no opt-out, so content now runs under the status and navigation bars on Android too. React Native 0.81 therefore deprecated `SafeAreaView`; in 0.87 it still exists but warns that it will be removed. Use `react-native-safe-area-context` instead. Put `SafeAreaProvider` at the root, and use its `SafeAreaView` with `edges` (all four by default, with your own padding added on top) or `useSafeAreaInsets()` to pad specific pieces. For example, pad the chat header by `insets.top` and the composer by `insets.bottom`.

code

tsx · 30 lines
tsx
import {Text, TextInput, View} from 'react-native';
import {
  SafeAreaProvider,
  SafeAreaView,
  initialWindowMetrics,
  useSafeAreaInsets,
} from 'react-native-safe-area-context';

function ChatScreen() {
  const insets = useSafeAreaInsets();
  return (
    <View style={{flex: 1}}>
      <SafeAreaView edges={['top', 'left', 'right']} style={{backgroundColor: '#1f6feb'}}>
        <Text style={{padding: 12, color: '#ffffff'}}>Team chat</Text>
      </SafeAreaView>
      <View style={{flex: 1}} />
      <View style={{paddingHorizontal: 12, paddingTop: 8, paddingBottom: 8 + insets.bottom}}>
        <TextInput placeholder="Message" />
      </View>
    </View>
  );
}

export default function App() {
  return (
    <SafeAreaProvider initialMetrics={initialWindowMetrics}>
      <ChatScreen />
    </SafeAreaProvider>
  );
}

go deeper

for a junior

Recall that core SafeAreaView is deprecated, and that react-native-safe-area-context provides SafeAreaProvider, SafeAreaView with edges, and useSafeAreaInsets.

for a middle

Explain why: core SafeAreaView is iOS-only padding, and Android edge-to-edge (forced for API 35 targets, mandatory on Android 16) means both platforms now need explicit insets.

for a senior

Apply insets per edge where UI meets the screen instead of wrapping everything, avoid double padding with navigator headers, and test Android versions with and without forced edge-to-edge.

for a principal

Plan the migration off core SafeAreaView before it is removed, and standardise one inset strategy in shared layout components so screens do not each reinvent it.

## What a safe area is Modern phones do not give an app a clean rectangle. There is a camera notch or island at the top, rounded corners, a home indicator or gesture bar at the bottom, and on Android status and navigation bars that the app now draws **behind**. The **safe area** is the part of the screen where content is not covered by any of these. Its size is expressed as four **insets**: top, right, bottom and left. ## Why core SafeAreaView is deprecated React Native ships a `SafeAreaView` component, but since **React Native 0.81 it is deprecated**. Using it in 0.87 logs a one-time warning that it "will be removed in a future release", and the docs mark it deprecated in favour of `react-native-safe-area-context`. The reasons, from the 0.81 release post and the component docs: - **It is iOS-only.** It was designed as limited iOS support and does nothing for Android. - **It is not compatible with Android edge-to-edge.** It cannot protect content that Android now draws under the system bars. - **It only applies padding**, and padding you set in its `style` is ignored, which gives different results per platform. - **It cannot be customised**: you cannot choose edges or read the inset values. ## Edge-to-edge made this urgent - On **Android 15**, apps that target API 35 are displayed edge to edge by the OS. - On **Android 16**, React Native's default target since 0.81, **there is no opt-out**. - React Native 0.81 added an **`edgeToEdgeEnabled`** Gradle property to turn edge-to-edge on for older Android versions too, so every version behaves the same. With edge-to-edge, the app's root view extends behind the status bar at the top and the navigation or gesture bar at the bottom, so insets must be applied deliberately on Android as well as iOS. The 0.77 release post notes that `react-native-safe-area-context` already handles forced edge-to-edge. ## Using react-native-safe-area-context 1. **Wrap the app once in `SafeAreaProvider`.** It measures the insets and provides them through context. Its docs note that it may also be needed at the root of modals. 2. **Use its `SafeAreaView`** where a whole container should avoid the unsafe areas. It is a regular `View` with the insets applied as padding. Its **`edges`** prop picks which sides to protect; the default is all four: `['top', 'right', 'bottom', 'left']`. Unlike the core component, padding you add yourself is **added** to the inset padding. 3. **Use `useSafeAreaInsets()`** when you need the numbers, for example to pad only a chat composer by `insets.bottom`, or to size a header by `insets.top`. It returns `{top, right, bottom, left}`. 4. **Optionally pass `initialWindowMetrics`** to the provider's `initialMetrics` to avoid a first frame without insets. The library's docs recommend its `SafeAreaView` where possible, because it applies insets natively and so tracks rotation without a delay, and the hook for more custom cases. ## Choosing edges on a chat screen | Area | Edge to protect | How | |---|---|---| | Header under the notch | top | `edges={['top']}` on the header container, or `paddingTop: insets.top` | | Message list | left, right (landscape) | `edges={['left', 'right']}` | | Composer above the home indicator | bottom | `paddingBottom: insets.bottom` on the composer | Protecting every edge on the root often double-pads when a navigator's header already handles the top, so apply insets where each piece of UI actually meets the screen edge. ## Testing insets properly Insets differ more than most teams expect, so test a small matrix rather than one device: 1. An iPhone with a notch or island, in portrait and landscape; landscape moves the large insets to the left and right. 2. An Android phone on Android 15 or later, with **gesture navigation** and again with **three-button navigation**. The bottom inset differs between the two. 3. An older Android version, with `edgeToEdgeEnabled` set the way you ship, to confirm that the layout matches. 4. A tablet or foldable, where insets can be zero on some edges. The `SafeAreaProvider` must be mounted in all of these runs, including inside modals, or the hook reports nothing useful. ## Common mistakes - Using core `SafeAreaView` and wondering why Android content sits under the status bar. - Forgetting `SafeAreaProvider`, which leaves the hook with no insets to read. - Wrapping the whole app in one `SafeAreaView`, which also pads the areas behind which a background colour should extend.

  • When would you use useSafeAreaInsets instead of react-native-safe-area-context's SafeAreaView?
    When only one piece needs an inset, or the inset feeds something other than padding: a composer's bottom padding, a header's height, an absolutely positioned button. `SafeAreaView` is the default choice for whole containers because it applies insets natively and tracks rotation without a delay; the hook re-renders with new values instead.
  • What does the edgeToEdgeEnabled Gradle property do in a React Native 0.81+ app?
    It turns on edge-to-edge for Android versions below 16, so the app draws behind the system bars everywhere, not only where the OS forces it. That gives one layout model to test across versions. On Android 16 edge-to-edge is mandatory regardless of this setting.

saying these in an interview costs you the question

  • Core SafeAreaView also protects content on Android.
  • Android apps can still opt out of edge-to-edge on Android 16.
  • useSafeAreaInsets works without a SafeAreaProvider above it.
  • Padding set on safe-area-context's SafeAreaView replaces the inset padding.
  • Wrapping the whole app in one SafeAreaView is always the right fix.