Skip to content

fix: View, FloatingButton, Toast - keep content clear of the iOS 26 bottom tab bar - #4052

Merged
yedidyak merged 12 commits into
masterfrom
fix/View_useSafeArea_iOS
Nov 11, 2026
Merged

yedidyak merged 12 commits into
masterfrom
fix/View_useSafeArea_iOS

Conversation

@yedidyak

@yedidyak yedidyak commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Description

On iOS 26 with the Liquid Glass tab bar, apps can draw screen content behind a floating translucent bottom tab bar. This PR fixes three components that misplace content in that layout.

Constants.isLiquidGlass. All three changes are gated on a new Constants.isLiquidGlass flag. It is on by default on iOS 26 and later, matching Xcode's default (apps built with the iOS 26 SDK get Liquid Glass unless they set UIDesignRequiresCompatibility, and Xcode 27 drops that opt-out), and always off on Android, web and iOS < 26 (setting it there has no effect). Apps that still opt out with UIDesignRequiresCompatibility set Constants.isLiquidGlass = false before the first render to keep the previous layout. Android, web and iOS < 26 are unchanged throughout.

View useSafeArea. View with useSafeArea renders react-native-safe-area-context's SafeAreaView whenever that package is installed. That component pads every edge from the nearest SafeAreaProvider's insets regardless of where the view sits, so a header or spacer at the top of a screen gets bottom padding whenever the provider's view extends under the bar (provider bottom inset = tab bar + home indicator). A useSafeArea header grows by the tab bar height and <View useSafeArea/> spacers become visible bands.
With Constants.isLiquidGlass on, a useSafeArea view that sets no padding and no edges/mode renders React Native's SafeAreaView, which UIKit insets only on the edges the view actually touches (a top header gets the status bar, a bottom footer gets the bar, a view in the middle gets nothing). Elsewhere it keeps the react-native-safe-area-context SafeAreaView when installed, and React Native's SafeAreaView on iOS otherwise. Views that set padding (modifiers or style) or pass edges/mode keep react-native-safe-area-context's SafeAreaView exactly as before, because React Native's SafeAreaView replaces the view's own padding with the insets and has no edges. With the flag on, a padding-free useSafeArea view that does not touch an edge no longer gets padding for that edge. The container is chosen once, when the view mounts: padding added later does not remount it but is ignored by React Native's SafeAreaView (a dev warning says so), and changing the flag after mount does not affect mounted views, and views with animated or reanimated also keep react-native-safe-area-context's SafeAreaView, since animated padding is not visible to the check.

FloatingButton. It renders through ScreenFooter and pads its content by a fixed spacing (or bottomMargin), so on a tab screen its buttons sit under the bar and can't be tapped. With the flag on it adds the bottom safe-area inset from the nearest react-native-safe-area-context provider to the footer's bottom padding, with or without a custom bottomMargin, and a hoisted button drops it as the keyboard starts to show (keyboardWillShow/keyboardWillHide, starting from Keyboard.isVisible()), so it does not jump at the end of the keyboard animation. A sticky button keeps the inset. The inset comes from the nearest provider, so a FloatingButton inside a Modal or sheet opened from a tab screen should be wrapped in its own SafeAreaProvider. Without a provider (or without the package) nothing is added, and a FloatingButton with no buttons still renders nothing outside a provider.

Toast (incubator). While a Toast is hidden, its renderAttachment content (for example a bottom action bar) is rendered in a plain positioned View at the bottom of the screen, so on a tab screen it sits under the bar. With the flag on that container uses useSafeArea for bottom-positioned toasts (top attachments stay flush with the top), so with the View change above it insets only the bottom edge it touches.

No new props. New: Constants.isLiquidGlass (getter and setter). Validated with yarn build:dev, lint (0 errors) and the full react-native-ui-lib jest suite (982 passed). New tests cover Constants.isLiquidGlass, the View container choice (padding, edges, mode, flag changes after mount), the FloatingButton inset (keyboard, no provider, bottomMargin, no buttons) and the Toast attachment.

What changes on iOS 26 by default

  • FloatingButton: its bottom padding includes the screen's bottom safe-area inset (home indicator, or tab bar + home indicator when the screen draws behind a translucent bar), also on top of bottomMargin.
  • Padding-free useSafeArea views inset only the edges they touch, instead of every edge. This includes ui-lib's own users of useSafeArea: incubator and legacy Toast, ActionBar, Modal TopBar, ConnectionStatusBar, Dialog, Picker / PickerDialog spacers.
  • Incubator Toast: a hidden bottom attachment stays inside the safe area (bottom, and left/right in landscape).
  • On React Native 0.81 and later, the first padding-free useSafeArea view logs React Native's SafeAreaView deprecation warning in development.
    Apps that opt out of Liquid Glass set Constants.isLiquidGlass = false before the first render to keep today's layout. The default follows the OS version, so this also applies to binaries built with an SDK older than iOS 26 (which run without Liquid Glass) that receive new JavaScript over the air.

Changelog

  • Constants - new isLiquidGlass flag, on by default on iOS 26 and later; apps that opt out of Liquid Glass with UIDesignRequiresCompatibility set it to false.
  • View - on iOS 26 and later, useSafeArea insets only the edges the view touches (React Native SafeAreaView), so headers and spacers no longer pick up the bottom inset under translucent tab bars.
  • FloatingButton - on iOS 26 and later, adds the bottom safe-area inset so the button stays above translucent bottom tab bars.
  • Toast - on iOS 26 and later, the attachment shown while the toast is hidden stays above translucent bottom tab bars.

Additional info

Needed for iOS 26 Liquid Glass tab bars in Wix apps; consumed by wix-react-native-ui-lib. Combines the former #4063 and #4064.

…eArea on iOS

react-native-safe-area-context's SafeAreaView pads every edge from the nearest
SafeAreaProvider's insets regardless of where the view sits, so a header with
useSafeArea gets bottom padding whenever the provider extends under a
translucent tab bar (iOS 26 Liquid Glass). React Native's SafeAreaView insets
only the edges the view actually touches, which is what useSafeArea means.
Other platforms keep the safe-area-context SafeAreaView when it is installed.
@github-actions

Copy link
Copy Markdown
Contributor

✅ PR Description Validation Passed

All required sections are properly filled out:

  • ✅ Description
  • ✅ Changelog
  • ✅ Additional info

Your PR is good for review! 🚀


This validation ensures all sections from the PR template are properly filled.

…and later

Android, web and iOS < 26 keep react-native-safe-area-context's SafeAreaView when it is installed, exactly as before.
@yedidyak yedidyak changed the title fix: View - use React Native's position-aware SafeAreaView for useSafeArea on iOS fix: View - use React Native's position-aware SafeAreaView for useSafeArea on iOS 26 Oct 30, 2026
On iOS 26 and later the footer adds the bottom safe-area inset, so a FloatingButton on a screen that draws behind a translucent tab bar stays above it. Android, web and iOS < 26 are unchanged.
On iOS 26 and later the attachment rendered while the toast is hidden uses useSafeArea, so it stays inside the safe area instead of under a translucent tab bar. Android, web and iOS < 26 are unchanged.
@yedidyak yedidyak changed the title fix: View - use React Native's position-aware SafeAreaView for useSafeArea on iOS 26 fix: View, FloatingButton, Toast - keep content clear of the iOS 26 bottom tab bar Nov 3, 2026
…oast attachments flush, and drop the FloatingButton inset as the keyboard starts to show
…added later, and drop the FloatingButton inset only when hoisted
@yedidyak
yedidyak merged commit d9ab2e6 into master Nov 11, 2026
5 checks passed
@yedidyak
yedidyak deleted the fix/View_useSafeArea_iOS branch November 11, 2026 11:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants