CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-native-screens

Native navigation primitives for React Native apps with native screen management and transitions.

Pending
Overview
Eval results
Files

experimental-features.mddocs/

Experimental Features

Beta and experimental components for advanced navigation patterns including bottom tabs, split views, and experimental screen hosting. These features are under active development and may change in future versions.

Core Imports

import {
  BottomTabs,
  BottomTabsScreen,
  ScreenStackHost,
  StackScreen,
  StackScreenLifecycleState,
  SplitViewHost,
  SplitViewScreen
} from "react-native-screens";

Capabilities

Bottom Tabs

Experimental native bottom tabs component that provides platform-native tab bar functionality with improved performance over JavaScript-based implementations.

/**
 * Experimental native bottom tabs component
 */
function BottomTabs(props: BottomTabsProps): JSX.Element;

interface BottomTabsProps {
  /** Currently selected tab index */
  selectedTab?: number;
  
  /** Callback when tab selection changes */
  onTabChange?: (event: NativeSyntheticEvent<NativeFocusChangeEvent>) => void;
  
  /** Whether tabs should be scrollable (Android) */
  scrollable?: boolean;
  
  /** Tab bar background color */
  barTintColor?: ColorValue;
  
  /** Selected tab tint color */
  selectedItemColor?: ColorValue;
  
  /** Unselected tab tint color */
  unselectedItemColor?: ColorValue;
  
  /** Tab bar style (iOS) */
  barStyle?: 'default' | 'black';
  
  /** Whether tab bar is translucent (iOS) */
  translucent?: boolean;
  
  /** Tab bar appearance (iOS) */
  appearance?: 'default' | 'opaque';
  
  /** Content inset adjustment behavior (iOS) */
  contentInsetAdjustmentBehavior?: 'automatic' | 'scrollableAxes' | 'never' | 'always';
}

interface NativeFocusChangeEvent {
  /** Index of the newly focused tab */
  focusedTab: number;
  
  /** Index of the previously focused tab */
  previouslyFocusedTab: number;
}

Usage Example:

import React, { useState } from 'react';
import { BottomTabs, BottomTabsScreen } from 'react-native-screens';
import { View, Text } from 'react-native';

function TabNavigator() {
  const [selectedTab, setSelectedTab] = useState(0);

  const handleTabChange = (event) => {
    setSelectedTab(event.nativeEvent.focusedTab);
  };

  return (
    <BottomTabs
      selectedTab={selectedTab}
      onTabChange={handleTabChange}
      barTintColor="#f8f9fa"
      selectedItemColor="#007AFF"
      unselectedItemColor="#8E8E93"
    >
      <BottomTabsScreen
        title="Home"
        tabBarIcon="home"
        badge="3"
      >
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
          <Text>Home Tab Content</Text>
        </View>
      </BottomTabsScreen>
      
      <BottomTabsScreen
        title="Search"
        tabBarIcon="search"
      >
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
          <Text>Search Tab Content</Text>
        </View>
      </BottomTabsScreen>
      
      <BottomTabsScreen
        title="Profile"
        tabBarIcon="person"
      >
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
          <Text>Profile Tab Content</Text>
        </View>
      </BottomTabsScreen>
    </BottomTabs>
  );
}

Bottom Tabs Screen

Individual screen component within the bottom tabs navigator that represents a single tab with its content and configuration.

/**
 * Individual screen within bottom tabs
 */
function BottomTabsScreen(props: BottomTabsScreenProps): JSX.Element;

interface BottomTabsScreenProps {
  /** Tab title */
  title?: string;
  
  /** Tab bar icon name or component */
  tabBarIcon?: string | React.ComponentType<any>;
  
  /** Badge text to display on tab */
  badge?: string;
  
  /** Badge background color */
  badgeColor?: ColorValue;
  
  /** Whether tab is enabled */
  enabled?: boolean;
  
  /** Tab tint color when selected */
  activeTintColor?: ColorValue;
  
  /** Tab tint color when unselected */
  inactiveTintColor?: ColorValue;
  
  /** Tab background color */
  backgroundColor?: ColorValue;
  
  /** Whether tab should show title */
  showTitle?: boolean;
  
  /** Custom tab bar component */
  tabBarComponent?: React.ComponentType<any>;
  
  /** Tab press callback */
  onTabPress?: () => void;
  
  /** Tab long press callback */
  onTabLongPress?: () => void;
}

Advanced Usage:

import React from 'react';
import { BottomTabsScreen } from 'react-native-screens';
import { Image } from 'react-native';

function CustomTabIcon({ focused, color }) {
  return (
    <Image
      source={focused ? require('./home-filled.png') : require('./home-outline.png')}
      style={{ width: 24, height: 24, tintColor: color }}
    />
  );
}

function CustomBottomTabsScreen() {
  return (
    <BottomTabsScreen
      title="Home"
      tabBarIcon={CustomTabIcon}
      badge="5"
      badgeColor="#FF3B30"
      onTabPress={() => console.log('Home tab pressed')}
      onTabLongPress={() => console.log('Home tab long pressed')}
    >
      {/* Screen content */}
    </BottomTabsScreen>
  );
}

Screen Stack Host

Experimental screen stack host component that provides advanced screen stack management with enhanced lifecycle control.

/**
 * Experimental screen stack host component
 */
function ScreenStackHost(props: ViewProps): JSX.Element;

Usage Example:

import React from 'react';
import { ScreenStackHost, StackScreen } from 'react-native-screens';

function ExperimentalStackNavigator() {
  return (
    <ScreenStackHost>
      <StackScreen
        active={1}
        lifecycle={StackScreenLifecycleState.Active}
      >
        {/* Screen content */}
      </StackScreen>
    </ScreenStackHost>
  );
}

Stack Screen

Experimental stack screen component with enhanced lifecycle management and performance optimizations.

/**
 * Experimental stack screen component
 */
function StackScreen(props: StackScreenProps): JSX.Element;

interface StackScreenProps extends ViewProps {
  /** Screen active state */
  active?: 0 | 1;
  
  /** Screen lifecycle state */
  lifecycle?: StackScreenLifecycleState;
  
  /** Screen identifier */
  screenId?: string;
  
  /** Performance optimization settings */
  optimizationHints?: {
    /** Whether screen content should be preloaded */
    preload?: boolean;
    
    /** Whether screen should be kept in memory */
    keepAlive?: boolean;
    
    /** Priority level for resource allocation */
    priority?: 'low' | 'normal' | 'high';
  };
}

Stack Screen Lifecycle State

Enumeration of lifecycle states for stack screens, providing fine-grained control over screen behavior.

/**
 * Lifecycle states for stack screens
 */
enum StackScreenLifecycleState {
  /** Screen is not yet initialized */
  Uninitialized = 0,
  
  /** Screen is being created */
  Creating = 1,
  
  /** Screen is active and visible */
  Active = 2,
  
  /** Screen is inactive but still in memory */
  Inactive = 3,
  
  /** Screen is being destroyed */
  Destroying = 4,
  
  /** Screen has been destroyed */
  Destroyed = 5
}

Usage Example:

import React, { useEffect } from 'react';
import { StackScreen, StackScreenLifecycleState } from 'react-native-screens';

function LifecycleAwareScreen({ lifecycle }) {
  useEffect(() => {
    switch (lifecycle) {
      case StackScreenLifecycleState.Creating:
        console.log('Screen is being created');
        break;
      case StackScreenLifecycleState.Active:
        console.log('Screen is now active');
        break;
      case StackScreenLifecycleState.Inactive:
        console.log('Screen is now inactive');
        break;
      case StackScreenLifecycleState.Destroying:
        console.log('Screen is being destroyed');
        break;
    }
  }, [lifecycle]);

  return (
    <StackScreen
      lifecycle={lifecycle}
      optimizationHints={{
        preload: true,
        keepAlive: false,
        priority: 'normal'
      }}
    >
      {/* Screen content */}
    </StackScreen>
  );
}

Split View Host

Host component for split view layouts, primarily designed for iPad and larger screens to provide master-detail interfaces.

/**
 * Host component for split view layouts (iPad)
 */
function SplitViewHost(props: SplitViewHostProps): JSX.Element;

interface SplitViewHostProps extends ViewProps {
  /** Split view display mode */
  displayMode?: SplitViewDisplayMode;
  
  /** Primary column width */
  primaryColumnWidth?: number;
  
  /** Secondary column width */
  secondaryColumnWidth?: number;
  
  /** Minimum primary column width */
  minimumPrimaryColumnWidth?: number;
  
  /** Maximum primary column width */
  maximumPrimaryColumnWidth?: number;
  
  /** Preferred display mode */
  preferredDisplayMode?: SplitViewDisplayMode;
  
  /** Whether primary column is shown */
  showsPrimaryColumn?: boolean;
  
  /** Whether secondary column is shown */
  showsSecondaryColumn?: boolean;
  
  /** Callback when display mode changes */
  onDisplayModeChange?: (event: NativeSyntheticEvent<{ displayMode: SplitViewDisplayMode }>) => void;
  
  /** Callback when column visibility changes */
  onColumnVisibilityChange?: (event: NativeSyntheticEvent<{ 
    primaryVisible: boolean; 
    secondaryVisible: boolean; 
  }>) => void;
}

Usage Example:

import React, { useState } from 'react';
import { SplitViewHost, SplitViewScreen } from 'react-native-screens';
import { View, Text, FlatList, TouchableOpacity } from 'react-native';

function MasterDetailInterface() {
  const [selectedItem, setSelectedItem] = useState(null);
  const [displayMode, setDisplayMode] = useState('automatic');

  const handleDisplayModeChange = (event) => {
    setDisplayMode(event.nativeEvent.displayMode);
  };

  return (
    <SplitViewHost
      displayMode={displayMode}
      primaryColumnWidth={320}
      minimumPrimaryColumnWidth={250}
      maximumPrimaryColumnWidth={400}
      onDisplayModeChange={handleDisplayModeChange}
    >
      <SplitViewScreen column="primary">
        <View style={{ flex: 1, backgroundColor: '#f5f5f5' }}>
          <Text style={{ fontSize: 18, padding: 16 }}>Master</Text>
          <FlatList
            data={items}
            keyExtractor={(item) => item.id}
            renderItem={({ item }) => (
              <TouchableOpacity 
                onPress={() => setSelectedItem(item)}
                style={{ 
                  padding: 16, 
                  backgroundColor: selectedItem?.id === item.id ? '#007AFF' : 'white' 
                }}
              >
                <Text style={{ 
                  color: selectedItem?.id === item.id ? 'white' : 'black' 
                }}>
                  {item.title}
                </Text>
              </TouchableOpacity>
            )}
          />
        </View>
      </SplitViewScreen>
      
      <SplitViewScreen column="secondary">
        <View style={{ flex: 1, backgroundColor: 'white', padding: 16 }}>
          <Text style={{ fontSize: 18, marginBottom: 16 }}>Detail</Text>
          {selectedItem ? (
            <View>
              <Text style={{ fontSize: 16, fontWeight: 'bold' }}>
                {selectedItem.title}
              </Text>
              <Text style={{ marginTop: 8 }}>
                {selectedItem.description}
              </Text>
            </View>
          ) : (
            <Text style={{ color: '#8E8E93' }}>
              Select an item from the master list
            </Text>
          )}
        </View>
      </SplitViewScreen>
    </SplitViewHost>
  );
}

Split View Screen

Individual screen component within a split view layout, representing either the primary or secondary column content.

/**
 * Individual screen within split view
 */
function SplitViewScreen(props: SplitViewScreenProps): JSX.Element;

interface SplitViewScreenProps extends ViewProps {
  /** Which column this screen represents */
  column: 'primary' | 'secondary';
  
  /** Whether this column is currently visible */
  visible?: boolean;
  
  /** Column background color */
  backgroundColor?: ColorValue;
  
  /** Column border configuration */
  borderColor?: ColorValue;
  borderWidth?: number;
  
  /** Callback when column becomes visible */
  onAppear?: () => void;
  
  /** Callback when column becomes hidden */
  onDisappear?: () => void;
}

Types

Split View Display Mode

type SplitViewDisplayMode = 
  | 'automatic'              // System determines layout
  | 'secondaryOnly'          // Show only secondary column
  | 'oneBesideSecondary'     // Primary beside secondary
  | 'oneOverSecondary'       // Primary over secondary
  | 'twoBesideSecondary'     // Two columns beside secondary
  | 'twoOverSecondary'       // Two columns over secondary
  | 'twoDisplaceSecondary';  // Two columns displacing secondary

Feature Flags and Configuration

Enabling Experimental Features

import { featureFlags } from "react-native-screens";

// Enable experimental bottom tabs
featureFlags.experiment.controlledBottomTabs = true;

// Check if experimental features are available
if (featureFlags.experiment.controlledBottomTabs) {
  // Use experimental BottomTabs component
} else {
  // Use alternative implementation
}

Private API Access

// Import private debugging utilities (use with caution)
import { 
  internalEnableDetailedBottomTabsLogging,
  bottomTabsDebugLog 
} from "react-native-screens/private";

// Enable detailed logging for debugging (development only)
if (__DEV__) {
  internalEnableDetailedBottomTabsLogging(true);
  
  // Custom debug logging
  bottomTabsDebugLog('Custom debug message', { data: 'value' });
}

Platform Support

iOS Specific Features

  • Native UITabBarController integration for BottomTabs
  • UISplitViewController for split views
  • iOS-specific tab bar appearance options
  • Form sheet and popover presentations

Android Specific Features

  • Material Design bottom navigation
  • Fragment-based tab management
  • Scrollable tab bars
  • Android-specific navigation patterns

Compatibility Notes

  • Bottom tabs require iOS 11+ and Android API 21+
  • Split views are primarily designed for iPad but work on iPhone in landscape
  • Experimental features may have limited testing on all device configurations
  • Performance characteristics may vary between platforms

Migration and Stability

Stability Considerations

  • Experimental features are subject to breaking changes
  • APIs may be removed or significantly modified in future versions
  • Thorough testing recommended before production use
  • Consider feature flags for gradual rollout

Migration Path

// Gradual migration approach
import { featureFlags, BottomTabs } from "react-native-screens";

function ConditionalBottomTabs() {
  // Check if experimental features are stable enough
  const useExperimental = featureFlags.experiment.controlledBottomTabs && 
                         Platform.OS === 'ios' && // Start with iOS only
                         !__DEV__; // Production ready
  
  if (useExperimental) {
    return <BottomTabs {...props} />;
  }
  
  // Fallback to stable implementation
  return <LegacyBottomTabs {...props} />;
}

Testing Recommendations

  • Test on multiple device sizes and orientations
  • Verify performance characteristics meet requirements
  • Test edge cases and error scenarios
  • Monitor memory usage and performance metrics
  • Validate accessibility features work correctly

Install with Tessl CLI

npx tessl i tessl/npm-react-native-screens

docs

core-functions.md

experimental-features.md

header-components.md

index.md

navigation-utilities.md

screen-components.md

types-interfaces.md

tile.json