@life-hack-tools/splash
v1.2.0
Published
Composable Expo React Native splash sequence manager with injectable brand and app splash components.
Readme
@life-hack-tools/splash
Composable 2-stage splash screen manager for Expo React Native apps.
- Stage 1 (Brand): injectable brand splash component
- Stage 2 (App): injectable app-specific splash component
- Includes a default
BrandSplash, but apps can provide their own brand and app splash components.
Installation
npm install @life-hack-tools/splashPeer dependencies
Ensure these are installed in your Expo project:
expo-linear-gradientexpo-splash-screenexpo-status-barreact-native-reanimated
Usage
Basic (SplashManager)
Wrap your app content with SplashManager in the root layout:
import { BrandSplash, SplashManager } from '@life-hack-tools/splash';
import { MyAppSplash } from '@/components/MyAppSplash';
export default function RootLayout() {
const [appLoaded, setAppLoaded] = useState(false);
useEffect(() => {
// Load fonts, auth, etc.
loadResources().then(() => setAppLoaded(true));
}, []);
return (
<SplashManager
appLoaded={appLoaded}
BrandSplash={BrandSplash}
AppSplash={MyAppSplash}
brandSplashProps={{
letters: ['L', 'H', 'T'],
colors: ['#a51c1c', '#6b0a0a', '#1a0000'],
}}
appSplashProps={{
title: 'My App',
}}
brandDuration={1500}
appSplashDuration={2000}
onPrepare={async () => {
// Run startup work while splash screens are visible.
await loadResources();
}}
onReady={() => console.log('Splash done')}
onMount={() => {
// Optional app-level setup, e.g. system bar configuration.
}}
>
<Stack screenOptions={{ headerShown: false }}>
<Stack.Screen name="(tabs)" />
</Stack>
</SplashManager>
);
}Hiding the status bar on iOS (required as of 1.2.0)
BrandSplash hides the status bar on Android only. On iOS you must hide it
yourself from the consuming app's Stack:
const [splashDone, setSplashDone] = useState(false);
<SplashManager
/* ...as above... */
onReady={() => setSplashDone(true)}
>
<Stack
screenOptions={{
headerShown: false,
statusBarHidden: !splashDone,
statusBarAnimation: 'fade',
}}
>
<Stack.Screen name="(tabs)" />
</Stack>
</SplashManager>Why the package no longer does this for you: apps that show AdMob
interstitials must set UIViewControllerBasedStatusBarAppearance to true in
Info.plist — otherwise the ad's close button slides under the Dynamic Island
and stops receiving taps. With that key set, expo-status-bar's hidden prop
throws a redbox at launch (RCTStatusBarManager module requires that the
UIViewControllerBasedStatusBarAppearance key in the Info.plist is set to NO).
statusBarHidden on a Stack screen goes through the view controller's
prefersStatusBarHidden, so it keeps working with that key set. Verified with
react-native-screens 4.16.0.
If your app does not use AdMob you can skip this — the status bar will simply stay visible during the splash on iOS.
BrandSplash standalone
Use BrandSplash directly if you want full control over transitions:
import { BrandSplash } from '@life-hack-tools/splash';
// Default LHTz letters + red gradient
<BrandSplash />
// Custom letters and colors
<BrandSplash
letters={['M', 'u', 'g', 'g']}
colors={['#1a1a1a', '#2a2a2a', '#0c0c0c']}
locations={[0, 0.5, 1]}
/>
// No animation
<BrandSplash animated={false} />API
SplashManager
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| brandDuration | number | 1500 | Brand splash duration (ms) |
| appSplashDuration | number | 2000 | App splash duration (ms) |
| BrandSplash | React.ComponentType | bundled BrandSplash | Stage 1 component. Pass your own component to fully control the brand splash. |
| brandSplashProps | object | — | Props forwarded to the brand splash component. |
| AppSplash | React.ComponentType | — | Stage 2 component. If omitted, skips to content. |
| appSplashProps | object | — | Props forwarded to the app splash component. |
| onReady | () => void | — | Called when splash sequence finishes |
| onMount | () => void | — | Optional setup hook for app-level side effects |
| onPrepare | () => void \| Promise<void> | — | Startup work to run while splash screens are visible. The splash sequence waits for it before advancing. |
| appLoaded | boolean | true | Set to false while loading resources (fonts, auth). Splash stays until true. |
| children | ReactNode | — | App content shown after splash |
BrandSplash
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| letters | string[] | ['L','H','T','z'] | Letters to animate |
| colors | string[] | LHTz red gradient | Gradient background colors |
| locations | number[] | [0, 0.25, 0.5, 0.75, 1] | Gradient stops |
| animated | boolean | true | Animate letter entrances |
Splash flow
Native splash (static) → Brand splash (animated) → App splash (custom) → App contentThe native splash screen is hidden as soon as appLoaded becomes true. The brand splash then runs for brandDuration ms, followed by the app splash for appSplashDuration ms.
Publish
npm version patch
npm publish --access public