Skip to content

SafeAreaView is re-exported unwrapped from the safe-area-context shim: className silently no-ops (breaks flex-1 screen roots after v4 -> v5 migration) #386

Description

@Thomas-athletics

Summary

The react-native-safe-area-context shim wraps SafeAreaProvider (to expose the inset CSS variables) but re-exports everything else from the original package unwrapped:

// src/components/react-native-safe-area-context.native.tsx
export * from "react-native-safe-area-context";

export function SafeAreaProvider({ children, ...props }: SafeAreaProviderProps) { ... }

SafeAreaView is therefore the original component, and className on it is a silent no-op — no warning, no error.

Why this is painful

<SafeAreaView className="flex-1 ..."> is an extremely common screen-root pattern in NativeWind v4 apps (the v4 JSX transform made it work on any component). After migrating to NativeWind v5 / react-native-css, every such screen root silently loses flex: 1, the SafeAreaView collapses to content height, and ScrollViews inside shrink to zero — the entire screen body renders blank while headers/tab bars (styled via style objects) keep working.

Nothing catches it statically: tsc, jest, and expo export are all green (the CSS compiles fine; it just never reaches the component). We only found it via on-simulator UAT. In our app it affected 44 SafeAreaView className call sites, i.e. every screen.

Environment

  • react-native-css 3.0.7, nativewind 5.0.0-preview.4, tailwindcss 4.3.3
  • Expo SDK 57, React Native 0.86, New Architecture enabled, pnpm monorepo (hoisted)
  • Metro via withNativewind(config, { inlineVariables: false }), default globalClassNamePolyfill (true)

Repro

import { SafeAreaView } from "react-native-safe-area-context";

export default function Screen() {
  return (
    <SafeAreaView className="flex-1 bg-red-500">
      <Text>never gets a red full-height background</Text>
    </SafeAreaView>
  );
}

<View className="flex-1 bg-red-500"> in the same tree styles correctly, confirming the CSS pipeline itself works.

Suggested fix

Wrap SafeAreaView in the shim like the other intercepted components, e.g.:

import { SafeAreaView as OriginalSafeAreaView } from "react-native-safe-area-context";
import { useCssElement } from "react-native-css";

export function SafeAreaView(props: SafeAreaViewProps & { className?: string }) {
  return useCssElement(OriginalSafeAreaView, props, { className: "style" });
}

We are currently shipping exactly that as a local pnpm patch on dist/ (module + commonjs) and it fully restores v4 behavior — all screens render identically to our NativeWind 4 baseline.

More generally: a dev-mode warning when className is passed to a component that nothing intercepts would have turned a multi-hour debugging session into a one-line console message. Happy to open a PR for the SafeAreaView wrap if useful.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    auto-triagedIssue has been automatically triaged by the auto-triage workflowbugSomething isn't workingconfirmedBug reproduced and confirmed by triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions