Native navigation primitives for React Native apps with native screen management and transitions.
—
Utility functions, hooks, and configuration objects that provide additional navigation behavior and integration capabilities. These utilities enhance the core screen functionality with platform-specific features and performance optimizations.
import {
executeNativeBackPress,
isSearchBarAvailableForCurrentPlatform,
useTransitionProgress,
ScreenContext,
compatibilityFlags,
featureFlags
} from "react-native-screens";Executes the native back press behavior on Android, which typically exits the application or navigates to the previous activity.
/**
* Executes native back press behavior, exits the app on Android
* @returns Always returns true to indicate the event was handled
*/
function executeNativeBackPress(): boolean;Usage Example:
import { executeNativeBackPress } from "react-native-screens";
import { BackHandler, Platform } from "react-native";
// Custom back handler that can exit the app
function handleBackPress() {
// Perform custom logic
if (canExit) {
if (Platform.OS === 'android') {
return executeNativeBackPress();
}
}
return false; // Let default behavior handle it
}
// Register back handler
BackHandler.addEventListener('hardwareBackPress', handleBackPress);Platform Behavior:
true to indicate the event was handledBoolean constant indicating whether the SearchBar component is available on the current platform.
/**
* Boolean indicating if SearchBar is available on the current platform
*/
const isSearchBarAvailableForCurrentPlatform: boolean;Usage Example:
import {
isSearchBarAvailableForCurrentPlatform,
SearchBar
} from "react-native-screens";
function ConditionalSearchScreen() {
return (
<View>
{isSearchBarAvailableForCurrentPlatform ? (
<SearchBar placeholder="Search..." />
) : (
<TextInput placeholder="Search..." />
)}
</View>
);
}Platform Support:
true - Native UISearchController integrationtrue - Material Design search viewfalse - Use fallback componentsHook that provides transition progress information for native stack screens. Allows for custom animations and UI updates based on screen transition state.
/**
* Hook that provides transition progress information for native stack screens
* @returns Transition progress context value with animation data
* @throws Error if used outside a native stack screen
*/
function useTransitionProgress(): TransitionProgressContext;
interface TransitionProgressContext {
/** Current transition progress (0-1) */
progress: Animated.Value;
/** Whether the screen is being closed (0 or 1) */
closing: Animated.Value;
/** Whether navigation is going forward (0 or 1) */
goingForward: Animated.Value;
}Usage Example:
import React from 'react';
import { useTransitionProgress } from "react-native-screens";
import { Animated } from 'react-native';
function AnimatedScreen() {
const { progress, closing, goingForward } = useTransitionProgress();
const scale = progress.interpolate({
inputRange: [0, 1],
outputRange: [0.8, 1],
});
const opacity = progress.interpolate({
inputRange: [0, 1],
outputRange: [0, 1],
});
return (
<Animated.View style={[
{ flex: 1 },
{
transform: [{ scale }],
opacity,
}
]}>
{/* Screen content */}
</Animated.View>
);
}Advanced Usage:
import React from 'react';
import { useTransitionProgress } from "react-native-screens";
import { Animated, View } from 'react-native';
function ComplexTransitionScreen() {
const { progress, closing, goingForward } = useTransitionProgress();
// Different animations for push vs pop
const headerTranslateY = Animated.multiply(
goingForward,
progress.interpolate({
inputRange: [0, 1],
outputRange: [-50, 0],
})
);
const contentOpacity = progress.interpolate({
inputRange: [0, 1],
outputRange: [0, 1],
});
return (
<View style={{ flex: 1 }}>
<Animated.View style={[
{ height: 60, backgroundColor: '#007AFF' },
{ transform: [{ translateY: headerTranslateY }] }
]} />
<Animated.View style={[
{ flex: 1 },
{ opacity: contentOpacity }
]}>
{/* Screen content */}
</Animated.View>
</View>
);
}React context that allows swapping the Screen component implementation. This is primarily used for enhanced integrations like Reanimated support.
/**
* React context for swapping Screen component implementation
*/
const ScreenContext: React.Context<React.ComponentType<ScreenProps>>;Usage Example:
import React from 'react';
import { ScreenContext, InnerScreen } from "react-native-screens";
import { CustomReanimatedScreen } from './CustomReanimatedScreen';
// Provider that allows using enhanced screen implementation
function EnhancedScreenProvider({ children, useReanimatedScreen = false }) {
const ScreenImplementation = useReanimatedScreen ? CustomReanimatedScreen : InnerScreen;
return (
<ScreenContext.Provider value={ScreenImplementation}>
{children}
</ScreenContext.Provider>
);
}
// Consumer that uses the context
function ScreenConsumer(props) {
const ScreenWrapper = React.useContext(ScreenContext) || InnerScreen;
return <ScreenWrapper {...props} />;
}Note: This context is primarily used internally and for advanced integrations. Most applications should use the standard Screen component directly.
Configuration object that exposes compatibility information for downstream navigation libraries to detect feature availability and maintain backward compatibility.
/**
* Exposes compatibility information for downstream navigation libraries
*/
const compatibilityFlags: CompatibilityFlags;
interface CompatibilityFlags {
/** Indicates new back title implementation (v3.21+) */
isNewBackTitleImplementation: boolean;
/** Indicates new header implementation (v4.0+) */
usesHeaderFlexboxImplementation: boolean;
}Usage Example:
import { compatibilityFlags } from "react-native-screens";
// Library code that needs to handle different versions
function configureHeaderLayout() {
if (compatibilityFlags.usesHeaderFlexboxImplementation) {
// Use new flexbox-based header layout
return { flex: 1, justifyContent: 'center' };
} else {
// Use legacy header layout
return { position: 'absolute', top: 0, left: 0, right: 0 };
}
}
function configureBackButton() {
if (compatibilityFlags.isNewBackTitleImplementation) {
// Use new back title system
return { backTitle: 'Back', backTitleVisible: true };
} else {
// Use legacy back button handling
return { backButtonTitle: 'Back' };
}
}Configuration object for controlling experimental and stable features globally across the application.
/**
* Configurable global behavior flags
*/
const featureFlags: FeatureFlags;
interface FeatureFlags {
/** Experimental feature flags */
experiment: {
/** Experimental bottom tabs control */
controlledBottomTabs: boolean;
};
/** Stable configuration flags (currently empty) */
stable: {};
}Usage Example:
import { featureFlags } from "react-native-screens";
// Enable experimental bottom tabs
featureFlags.experiment.controlledBottomTabs = true;
// Check if experimental features are enabled
function useExperimentalBottomTabs() {
return featureFlags.experiment.controlledBottomTabs;
}
function ConditionalBottomTabs() {
if (useExperimentalBottomTabs()) {
return <ExperimentalBottomTabs />;
}
return <StandardBottomTabs />;
}import { useTransitionProgress } from "react-native-screens";
import { useRoute, useNavigation } from "@react-navigation/native";
function ReactNavigationIntegration() {
const route = useRoute();
const navigation = useNavigation();
// Use transition progress for custom animations
const { progress } = useTransitionProgress();
// Combine with React Navigation hooks
const isScreenFocused = navigation.isFocused();
return (
<View>
<Text>Route: {route.name}</Text>
<Text>Focused: {isScreenFocused ? 'Yes' : 'No'}</Text>
</View>
);
}import {
executeNativeBackPress,
useTransitionProgress,
ScreenContext
} from "react-native-screens";
function CustomNavigationSystem({ children }) {
const handleBackPress = useCallback(() => {
// Custom back handling logic
if (canGoBack) {
goBack();
return true;
}
// Exit app on Android
return executeNativeBackPress();
}, [canGoBack, goBack]);
return (
<ScreenContext.Provider value={{ isActive: true, screenId: 'custom' }}>
{children}
</ScreenContext.Provider>
);
}import { useTransitionProgress } from "react-native-screens";
function PerformanceMonitor() {
const { progress } = useTransitionProgress();
useEffect(() => {
const listener = progress.addListener(({ value }) => {
// Monitor transition performance
console.log('Transition progress:', value);
if (value === 1) {
console.log('Transition completed');
// Log performance metrics
}
});
return () => progress.removeListener(listener);
}, [progress]);
return null;
}import { executeNativeBackPress } from "react-native-screens";
import { BackHandler, Platform } from "react-native";
function setupAndroidBackHandler() {
if (Platform.OS !== 'android') return;
const handleBackPress = () => {
// Custom logic before exiting
if (shouldExit()) {
executeNativeBackPress();
return true;
}
return false;
};
BackHandler.addEventListener('hardwareBackPress', handleBackPress);
return () => {
BackHandler.removeEventListener('hardwareBackPress', handleBackPress);
};
}import {
isSearchBarAvailableForCurrentPlatform,
SearchBar
} from "react-native-screens";
function iOSSearchIntegration() {
if (!isSearchBarAvailableForCurrentPlatform) {
return null;
}
return (
<SearchBar
placeholder="Search..."
placement="stacked"
hideWhenScrolling={true}
/>
);
}import { ScreenContext } from "react-native-screens";
function useScreenContext() {
const context = useContext(ScreenContext);
if (!context) {
throw new Error(
'useScreenContext must be used within a Screen component'
);
}
return context;
}import { useTransitionProgress } from "react-native-screens";
function SafeTransitionHook() {
try {
const progress = useTransitionProgress();
return progress;
} catch (error) {
console.warn('useTransitionProgress called outside native stack screen');
return null;
}
}Install with Tessl CLI
npx tessl i tessl/npm-react-native-screens