0
# Experimental Features
1
2
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.
3
4
## Core Imports
5
6
```typescript
7
import {
8
BottomTabs,
9
BottomTabsScreen,
10
ScreenStackHost,
11
StackScreen,
12
StackScreenLifecycleState,
13
SplitViewHost,
14
SplitViewScreen
15
} from "react-native-screens";
16
```
17
18
## Capabilities
19
20
### Bottom Tabs
21
22
Experimental native bottom tabs component that provides platform-native tab bar functionality with improved performance over JavaScript-based implementations.
23
24
```typescript { .api }
25
/**
26
* Experimental native bottom tabs component
27
*/
28
function BottomTabs(props: BottomTabsProps): JSX.Element;
29
30
interface BottomTabsProps {
31
/** Currently selected tab index */
32
selectedTab?: number;
33
34
/** Callback when tab selection changes */
35
onTabChange?: (event: NativeSyntheticEvent<NativeFocusChangeEvent>) => void;
36
37
/** Whether tabs should be scrollable (Android) */
38
scrollable?: boolean;
39
40
/** Tab bar background color */
41
barTintColor?: ColorValue;
42
43
/** Selected tab tint color */
44
selectedItemColor?: ColorValue;
45
46
/** Unselected tab tint color */
47
unselectedItemColor?: ColorValue;
48
49
/** Tab bar style (iOS) */
50
barStyle?: 'default' | 'black';
51
52
/** Whether tab bar is translucent (iOS) */
53
translucent?: boolean;
54
55
/** Tab bar appearance (iOS) */
56
appearance?: 'default' | 'opaque';
57
58
/** Content inset adjustment behavior (iOS) */
59
contentInsetAdjustmentBehavior?: 'automatic' | 'scrollableAxes' | 'never' | 'always';
60
}
61
62
interface NativeFocusChangeEvent {
63
/** Index of the newly focused tab */
64
focusedTab: number;
65
66
/** Index of the previously focused tab */
67
previouslyFocusedTab: number;
68
}
69
```
70
71
**Usage Example:**
72
73
```typescript
74
import React, { useState } from 'react';
75
import { BottomTabs, BottomTabsScreen } from 'react-native-screens';
76
import { View, Text } from 'react-native';
77
78
function TabNavigator() {
79
const [selectedTab, setSelectedTab] = useState(0);
80
81
const handleTabChange = (event) => {
82
setSelectedTab(event.nativeEvent.focusedTab);
83
};
84
85
return (
86
<BottomTabs
87
selectedTab={selectedTab}
88
onTabChange={handleTabChange}
89
barTintColor="#f8f9fa"
90
selectedItemColor="#007AFF"
91
unselectedItemColor="#8E8E93"
92
>
93
<BottomTabsScreen
94
title="Home"
95
tabBarIcon="home"
96
badge="3"
97
>
98
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
99
<Text>Home Tab Content</Text>
100
</View>
101
</BottomTabsScreen>
102
103
<BottomTabsScreen
104
title="Search"
105
tabBarIcon="search"
106
>
107
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
108
<Text>Search Tab Content</Text>
109
</View>
110
</BottomTabsScreen>
111
112
<BottomTabsScreen
113
title="Profile"
114
tabBarIcon="person"
115
>
116
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
117
<Text>Profile Tab Content</Text>
118
</View>
119
</BottomTabsScreen>
120
</BottomTabs>
121
);
122
}
123
```
124
125
### Bottom Tabs Screen
126
127
Individual screen component within the bottom tabs navigator that represents a single tab with its content and configuration.
128
129
```typescript { .api }
130
/**
131
* Individual screen within bottom tabs
132
*/
133
function BottomTabsScreen(props: BottomTabsScreenProps): JSX.Element;
134
135
interface BottomTabsScreenProps {
136
/** Tab title */
137
title?: string;
138
139
/** Tab bar icon name or component */
140
tabBarIcon?: string | React.ComponentType<any>;
141
142
/** Badge text to display on tab */
143
badge?: string;
144
145
/** Badge background color */
146
badgeColor?: ColorValue;
147
148
/** Whether tab is enabled */
149
enabled?: boolean;
150
151
/** Tab tint color when selected */
152
activeTintColor?: ColorValue;
153
154
/** Tab tint color when unselected */
155
inactiveTintColor?: ColorValue;
156
157
/** Tab background color */
158
backgroundColor?: ColorValue;
159
160
/** Whether tab should show title */
161
showTitle?: boolean;
162
163
/** Custom tab bar component */
164
tabBarComponent?: React.ComponentType<any>;
165
166
/** Tab press callback */
167
onTabPress?: () => void;
168
169
/** Tab long press callback */
170
onTabLongPress?: () => void;
171
}
172
```
173
174
**Advanced Usage:**
175
176
```typescript
177
import React from 'react';
178
import { BottomTabsScreen } from 'react-native-screens';
179
import { Image } from 'react-native';
180
181
function CustomTabIcon({ focused, color }) {
182
return (
183
<Image
184
source={focused ? require('./home-filled.png') : require('./home-outline.png')}
185
style={{ width: 24, height: 24, tintColor: color }}
186
/>
187
);
188
}
189
190
function CustomBottomTabsScreen() {
191
return (
192
<BottomTabsScreen
193
title="Home"
194
tabBarIcon={CustomTabIcon}
195
badge="5"
196
badgeColor="#FF3B30"
197
onTabPress={() => console.log('Home tab pressed')}
198
onTabLongPress={() => console.log('Home tab long pressed')}
199
>
200
{/* Screen content */}
201
</BottomTabsScreen>
202
);
203
}
204
```
205
206
### Screen Stack Host
207
208
Experimental screen stack host component that provides advanced screen stack management with enhanced lifecycle control.
209
210
```typescript { .api }
211
/**
212
* Experimental screen stack host component
213
*/
214
function ScreenStackHost(props: ViewProps): JSX.Element;
215
```
216
217
**Usage Example:**
218
219
```typescript
220
import React from 'react';
221
import { ScreenStackHost, StackScreen } from 'react-native-screens';
222
223
function ExperimentalStackNavigator() {
224
return (
225
<ScreenStackHost>
226
<StackScreen
227
active={1}
228
lifecycle={StackScreenLifecycleState.Active}
229
>
230
{/* Screen content */}
231
</StackScreen>
232
</ScreenStackHost>
233
);
234
}
235
```
236
237
### Stack Screen
238
239
Experimental stack screen component with enhanced lifecycle management and performance optimizations.
240
241
```typescript { .api }
242
/**
243
* Experimental stack screen component
244
*/
245
function StackScreen(props: StackScreenProps): JSX.Element;
246
247
interface StackScreenProps extends ViewProps {
248
/** Screen active state */
249
active?: 0 | 1;
250
251
/** Screen lifecycle state */
252
lifecycle?: StackScreenLifecycleState;
253
254
/** Screen identifier */
255
screenId?: string;
256
257
/** Performance optimization settings */
258
optimizationHints?: {
259
/** Whether screen content should be preloaded */
260
preload?: boolean;
261
262
/** Whether screen should be kept in memory */
263
keepAlive?: boolean;
264
265
/** Priority level for resource allocation */
266
priority?: 'low' | 'normal' | 'high';
267
};
268
}
269
```
270
271
### Stack Screen Lifecycle State
272
273
Enumeration of lifecycle states for stack screens, providing fine-grained control over screen behavior.
274
275
```typescript { .api }
276
/**
277
* Lifecycle states for stack screens
278
*/
279
enum StackScreenLifecycleState {
280
/** Screen is not yet initialized */
281
Uninitialized = 0,
282
283
/** Screen is being created */
284
Creating = 1,
285
286
/** Screen is active and visible */
287
Active = 2,
288
289
/** Screen is inactive but still in memory */
290
Inactive = 3,
291
292
/** Screen is being destroyed */
293
Destroying = 4,
294
295
/** Screen has been destroyed */
296
Destroyed = 5
297
}
298
```
299
300
**Usage Example:**
301
302
```typescript
303
import React, { useEffect } from 'react';
304
import { StackScreen, StackScreenLifecycleState } from 'react-native-screens';
305
306
function LifecycleAwareScreen({ lifecycle }) {
307
useEffect(() => {
308
switch (lifecycle) {
309
case StackScreenLifecycleState.Creating:
310
console.log('Screen is being created');
311
break;
312
case StackScreenLifecycleState.Active:
313
console.log('Screen is now active');
314
break;
315
case StackScreenLifecycleState.Inactive:
316
console.log('Screen is now inactive');
317
break;
318
case StackScreenLifecycleState.Destroying:
319
console.log('Screen is being destroyed');
320
break;
321
}
322
}, [lifecycle]);
323
324
return (
325
<StackScreen
326
lifecycle={lifecycle}
327
optimizationHints={{
328
preload: true,
329
keepAlive: false,
330
priority: 'normal'
331
}}
332
>
333
{/* Screen content */}
334
</StackScreen>
335
);
336
}
337
```
338
339
### Split View Host
340
341
Host component for split view layouts, primarily designed for iPad and larger screens to provide master-detail interfaces.
342
343
```typescript { .api }
344
/**
345
* Host component for split view layouts (iPad)
346
*/
347
function SplitViewHost(props: SplitViewHostProps): JSX.Element;
348
349
interface SplitViewHostProps extends ViewProps {
350
/** Split view display mode */
351
displayMode?: SplitViewDisplayMode;
352
353
/** Primary column width */
354
primaryColumnWidth?: number;
355
356
/** Secondary column width */
357
secondaryColumnWidth?: number;
358
359
/** Minimum primary column width */
360
minimumPrimaryColumnWidth?: number;
361
362
/** Maximum primary column width */
363
maximumPrimaryColumnWidth?: number;
364
365
/** Preferred display mode */
366
preferredDisplayMode?: SplitViewDisplayMode;
367
368
/** Whether primary column is shown */
369
showsPrimaryColumn?: boolean;
370
371
/** Whether secondary column is shown */
372
showsSecondaryColumn?: boolean;
373
374
/** Callback when display mode changes */
375
onDisplayModeChange?: (event: NativeSyntheticEvent<{ displayMode: SplitViewDisplayMode }>) => void;
376
377
/** Callback when column visibility changes */
378
onColumnVisibilityChange?: (event: NativeSyntheticEvent<{
379
primaryVisible: boolean;
380
secondaryVisible: boolean;
381
}>) => void;
382
}
383
```
384
385
**Usage Example:**
386
387
```typescript
388
import React, { useState } from 'react';
389
import { SplitViewHost, SplitViewScreen } from 'react-native-screens';
390
import { View, Text, FlatList, TouchableOpacity } from 'react-native';
391
392
function MasterDetailInterface() {
393
const [selectedItem, setSelectedItem] = useState(null);
394
const [displayMode, setDisplayMode] = useState('automatic');
395
396
const handleDisplayModeChange = (event) => {
397
setDisplayMode(event.nativeEvent.displayMode);
398
};
399
400
return (
401
<SplitViewHost
402
displayMode={displayMode}
403
primaryColumnWidth={320}
404
minimumPrimaryColumnWidth={250}
405
maximumPrimaryColumnWidth={400}
406
onDisplayModeChange={handleDisplayModeChange}
407
>
408
<SplitViewScreen column="primary">
409
<View style={{ flex: 1, backgroundColor: '#f5f5f5' }}>
410
<Text style={{ fontSize: 18, padding: 16 }}>Master</Text>
411
<FlatList
412
data={items}
413
keyExtractor={(item) => item.id}
414
renderItem={({ item }) => (
415
<TouchableOpacity
416
onPress={() => setSelectedItem(item)}
417
style={{
418
padding: 16,
419
backgroundColor: selectedItem?.id === item.id ? '#007AFF' : 'white'
420
}}
421
>
422
<Text style={{
423
color: selectedItem?.id === item.id ? 'white' : 'black'
424
}}>
425
{item.title}
426
</Text>
427
</TouchableOpacity>
428
)}
429
/>
430
</View>
431
</SplitViewScreen>
432
433
<SplitViewScreen column="secondary">
434
<View style={{ flex: 1, backgroundColor: 'white', padding: 16 }}>
435
<Text style={{ fontSize: 18, marginBottom: 16 }}>Detail</Text>
436
{selectedItem ? (
437
<View>
438
<Text style={{ fontSize: 16, fontWeight: 'bold' }}>
439
{selectedItem.title}
440
</Text>
441
<Text style={{ marginTop: 8 }}>
442
{selectedItem.description}
443
</Text>
444
</View>
445
) : (
446
<Text style={{ color: '#8E8E93' }}>
447
Select an item from the master list
448
</Text>
449
)}
450
</View>
451
</SplitViewScreen>
452
</SplitViewHost>
453
);
454
}
455
```
456
457
### Split View Screen
458
459
Individual screen component within a split view layout, representing either the primary or secondary column content.
460
461
```typescript { .api }
462
/**
463
* Individual screen within split view
464
*/
465
function SplitViewScreen(props: SplitViewScreenProps): JSX.Element;
466
467
interface SplitViewScreenProps extends ViewProps {
468
/** Which column this screen represents */
469
column: 'primary' | 'secondary';
470
471
/** Whether this column is currently visible */
472
visible?: boolean;
473
474
/** Column background color */
475
backgroundColor?: ColorValue;
476
477
/** Column border configuration */
478
borderColor?: ColorValue;
479
borderWidth?: number;
480
481
/** Callback when column becomes visible */
482
onAppear?: () => void;
483
484
/** Callback when column becomes hidden */
485
onDisappear?: () => void;
486
}
487
```
488
489
## Types
490
491
### Split View Display Mode
492
493
```typescript { .api }
494
type SplitViewDisplayMode =
495
| 'automatic' // System determines layout
496
| 'secondaryOnly' // Show only secondary column
497
| 'oneBesideSecondary' // Primary beside secondary
498
| 'oneOverSecondary' // Primary over secondary
499
| 'twoBesideSecondary' // Two columns beside secondary
500
| 'twoOverSecondary' // Two columns over secondary
501
| 'twoDisplaceSecondary'; // Two columns displacing secondary
502
```
503
504
## Feature Flags and Configuration
505
506
### Enabling Experimental Features
507
508
```typescript
509
import { featureFlags } from "react-native-screens";
510
511
// Enable experimental bottom tabs
512
featureFlags.experiment.controlledBottomTabs = true;
513
514
// Check if experimental features are available
515
if (featureFlags.experiment.controlledBottomTabs) {
516
// Use experimental BottomTabs component
517
} else {
518
// Use alternative implementation
519
}
520
```
521
522
### Private API Access
523
524
```typescript
525
// Import private debugging utilities (use with caution)
526
import {
527
internalEnableDetailedBottomTabsLogging,
528
bottomTabsDebugLog
529
} from "react-native-screens/private";
530
531
// Enable detailed logging for debugging (development only)
532
if (__DEV__) {
533
internalEnableDetailedBottomTabsLogging(true);
534
535
// Custom debug logging
536
bottomTabsDebugLog('Custom debug message', { data: 'value' });
537
}
538
```
539
540
## Platform Support
541
542
### iOS Specific Features
543
- Native UITabBarController integration for BottomTabs
544
- UISplitViewController for split views
545
- iOS-specific tab bar appearance options
546
- Form sheet and popover presentations
547
548
### Android Specific Features
549
- Material Design bottom navigation
550
- Fragment-based tab management
551
- Scrollable tab bars
552
- Android-specific navigation patterns
553
554
### Compatibility Notes
555
- Bottom tabs require iOS 11+ and Android API 21+
556
- Split views are primarily designed for iPad but work on iPhone in landscape
557
- Experimental features may have limited testing on all device configurations
558
- Performance characteristics may vary between platforms
559
560
## Migration and Stability
561
562
### Stability Considerations
563
- Experimental features are subject to breaking changes
564
- APIs may be removed or significantly modified in future versions
565
- Thorough testing recommended before production use
566
- Consider feature flags for gradual rollout
567
568
### Migration Path
569
```typescript
570
// Gradual migration approach
571
import { featureFlags, BottomTabs } from "react-native-screens";
572
573
function ConditionalBottomTabs() {
574
// Check if experimental features are stable enough
575
const useExperimental = featureFlags.experiment.controlledBottomTabs &&
576
Platform.OS === 'ios' && // Start with iOS only
577
!__DEV__; // Production ready
578
579
if (useExperimental) {
580
return <BottomTabs {...props} />;
581
}
582
583
// Fallback to stable implementation
584
return <LegacyBottomTabs {...props} />;
585
}
586
```
587
588
### Testing Recommendations
589
- Test on multiple device sizes and orientations
590
- Verify performance characteristics meet requirements
591
- Test edge cases and error scenarios
592
- Monitor memory usage and performance metrics
593
- Validate accessibility features work correctly