Hold the native launch screen until your app is ready
One.LaunchScreen holds the native launch screen past first content
until your startup work finishes: fonts, session, initial data. Prebuild
keeps the iOS storyboard and the Android system splash visible until
React Native draws; an app that reveals itself later stops that
automatic release and hides the screen itself.
On iOS hiding removes the launch view, with an optional fade. On
Android 12 and later, holding the screen with preventAutoHide also
hands the splash’s exit to One: hide lifts it at once or fades it,
instead of playing the system’s own animation. On web there is no
launch screen and the calls do nothing.
import { One } from 'one'
One.LaunchScreen.preventAutoHide()
async function loadInitialData() {}
async function startApp() { try { await loadInitialData() } finally { One.LaunchScreen.hide({ fade: true }) }}
void startApp()Call preventAutoHide at module evaluation time, before the first
render. Call hide once the app can paint its real first screen.
Both methods are synchronous. The hold applies to the current launch
only, so call preventAutoHide on each cold start that needs it. If
startup never prevents, the screen lifts with first content and hide
has nothing to do. hide stays safe to call again after the screen is
gone, which makes finally blocks and double-invoked effects harmless.
fade: true fades the launch screen out instead of removing it at
once. Android versions below 12 draw the launch screen as the window
background, which goes away at once.
One.LaunchScreen.Cover draws the configured launch screen in React
Native, exactly where the native one sits: the ground colour, the
background image, and the artwork at its configured width, centered, with
the dark variants. It reads the launch resources prebuild already bundled
into the app, so nothing is configured twice. Mount it above your first
screen, animate it, and call hide once it is drawn: the native screen
lifts away under it with no visible change.
import { useEffect, useState } from 'react'import Animated, { FadeOut } from 'react-native-reanimated'import { One } from 'one'
One.LaunchScreen.preventAutoHide()
export function Root({ children }: { children: React.ReactNode }) { const [covered, setCovered] = useState(true)
useEffect(() => { One.LaunchScreen.hide() const timer = setTimeout(() => setCovered(false), 400) return () => clearTimeout(timer) }, [])
return ( <> {children} {covered && ( <Animated.View exiting={FadeOut} style={{ position: 'absolute', inset: 0 }}> <One.LaunchScreen.Cover /> </Animated.View> )} </> )}Pass artwork={false} to draw only the ground and background image, and
put your own animated artwork in children. One.LaunchScreen.artworkWidth
is the configured width in points (null without native.app.splash); the
artwork is centered on the window. The cover is built from the resources
of the last prebuild, so rebuild the native app after changing the
splash. On web it renders nothing.
| Methods | Type | Description |
|---|---|---|
preventAutoHide() => voidHold the screen past first content. | () => void | Hold the screen past first content. |
hide(options?: LaunchScreenHideOptions) => voidHide the screen. Safe to repeat. | (options?: LaunchScreenHideOptions) => void | Hide the screen. Safe to repeat. |
CoverComponentType<LaunchScreenCoverProps>The configured launch screen drawn in React Native. | ComponentType<LaunchScreenCoverProps> | The configured launch screen drawn in React Native. |
artworkWidthnumber | nullThe configured artwork width in points. | number | null | The configured artwork width in points. |
| Cover props | Type | Description |
|---|---|---|
artworkbooleanDraw the artwork. Default true. | boolean | Draw the artwork. Default true. |
childrenReactNodeDrawn over the launch screen. | ReactNode | Drawn over the launch screen. |
| Hide options | Type | Description |
|---|---|---|
fadebooleanFade out instead of removing at once. | boolean | Fade out instead of removing at once. |
| iOS | Android | Web | |
|---|---|---|---|
| Screen | Storyboard | System splash | None |
| Hold | Past content | Past content | No effect |
| Fade | Optional | Android 12+ | No effect |
| Cover | Draws | Draws | Nothing |
| Repeat hide | Safe | Safe | Safe |
hide never lifts. Put the
call in a finally so failures still reveal the app.preventAutoHide on Android. Without a hold, the
system splash plays its own exit.Cover.import { useEffect, useState } from 'react'import { One } from 'one'
One.LaunchScreen.preventAutoHide()
function Gate({ children }: { children: React.ReactNode }) { const [ready, setReady] = useState(false)
useEffect(() => { async function start() { try { await Promise.all([loadFonts(), loadSession()]) } finally { setReady(true) One.LaunchScreen.hide({ fade: true }) } } void start() }, [])
if (!ready) return null return <>{children}</>}
async function loadFonts() {}async function loadSession() {}Preventing at module scope wins the race with first content. The gate renders nothing until startup settles, then reveals app and content together.
import { useEffect } from 'react'import { One } from 'one'
function useHideOnMount() { useEffect(() => { One.LaunchScreen.hide() }, [])}Screens with no startup work still benefit from an explicit hide in the root effect: it documents the handoff and stays harmless where nothing was held.
Edit this page on GitHub.