Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/src/tests/single-feature-tests/tabs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import TestTabsLifecycleEvents from './test-tabs-lifecycle-events';
import TestTabsItemTitle from './test-tabs-item-title';
import TestTabsSystemItem from './test-tabs-system-item-ios';
import TestTabsGeneralAppearanceNoLiquidGlass from './test-tabs-general-appearance-no-liquid-glass-ios';
import TestTabsNativeContainerStyle from './test-tabs-native-container-style';

const scenarios = {
TestTabBottomAccessory,
Expand All @@ -42,6 +43,7 @@ const scenarios = {
TestTabsItemTitle,
TestTabsSystemItem,
TestTabsGeneralAppearanceNoLiquidGlass,
TestTabsNativeContainerStyle,
};

const TabsScenarioGroup: ScenarioGroup<keyof typeof scenarios> = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
import {
TabsContainerWithHostConfigContext,
type TabRouteConfig,
useTabsHostConfig,
DEFAULT_TAB_ROUTE_OPTIONS,
} from '@apps/shared/gamma/containers/tabs';
import React from 'react';
import {
View,
Text,
ScrollView,
StyleSheet,
type ColorValue,
} from 'react-native';
import { scenarioDescription } from './scenario-description';
import { createScenario } from '@apps/tests/shared/helpers';
import { SettingsPicker } from '@apps/shared';
import { Colors } from '@apps/shared/styling';
type ContainerBackgroundOption = 'unset' | 'blue' | 'yellow' | 'purple';

function ConfigScreen() {
const { hostConfig, updateHostConfig } = useTabsHostConfig();

const getBackgroundColor = (
option: ContainerBackgroundOption,
): ColorValue | undefined => {
switch (option) {
case 'blue':
return Colors.BlueLight100;
case 'yellow':
return Colors.YellowLight100;
case 'purple':
return Colors.PurpleLight100;
case 'unset':
default:
return undefined;
}
};

const currentOption = (() => {
const bgColor = hostConfig.nativeContainerStyle?.backgroundColor;
if (bgColor === Colors.BlueLight100) return 'blue';
if (bgColor === Colors.YellowLight100) return 'yellow';
if (bgColor === Colors.PurpleLight100) return 'purple';
return 'unset';
})();
Comment thread
LKuchno marked this conversation as resolved.

return (
<ScrollView style={styles.container} contentContainerStyle={styles.content}>
<View style={styles.section}>
<Text style={styles.heading}>nativeContainerStyle</Text>
<Text style={styles.description}>
Controls the background color of the native container.
</Text>
</View>

<View style={styles.section}>
<Text style={styles.text}>
{'•'} On <Text style={{ fontWeight: '600' }}>Android</Text>: Color is
applied to the FrameLayout that wraps the focused screen and
BottomNavigationView
</Text>
</View>

<View style={styles.section}>
<Text style={styles.text}>
{'•'} On <Text style={{ fontWeight: '600' }}>iOS</Text>: Color is
applied to the UITabBarController's view
</Text>
</View>

<View style={styles.section}>
<Text style={styles.heading}>Background Color</Text>
<SettingsPicker<ContainerBackgroundOption>
label="backgroundColor"
value={currentOption}
onValueChange={option => {
updateHostConfig({
nativeContainerStyle: {
backgroundColor: getBackgroundColor(option),
},
});
}}
items={['unset', 'blue', 'yellow', 'purple']}
/>
</View>
</ScrollView>
);
}

function TabScreen() {
return (
<View style={styles.centeredContent}>
<Text style={styles.contentLabel}>Transparent Tab</Text>
<Text style={styles.contentHint}>
Observe the container background color behind the tab content and within the tab bar area.
</Text>
</View>
);
}

const ROUTE_CONFIGS: TabRouteConfig[] = [
{
name: 'Config',
Component: ConfigScreen,
options: {
...DEFAULT_TAB_ROUTE_OPTIONS,
title: 'Config',
ios: {
...DEFAULT_TAB_ROUTE_OPTIONS.ios,
scrollEdgeAppearance: {
tabBarBackgroundColor: Colors.RedDark100,
},
standardAppearance: {
tabBarBackgroundColor: Colors.RedDark100,
},
},
Comment on lines +109 to +117

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

android: {
...DEFAULT_TAB_ROUTE_OPTIONS.android,
standardAppearance: {
tabBarBackgroundColor: Colors.RedDark100,
tabBarItemActiveIndicatorEnabled: false,
},
},
},
},
{
name: 'Transparent',
Component: TabScreen,
options: {
...DEFAULT_TAB_ROUTE_OPTIONS,
title: 'Transparent',
android: {
...DEFAULT_TAB_ROUTE_OPTIONS.android,
standardAppearance: {
tabBarBackgroundColor: 'transparent',
tabBarItemActiveIndicatorEnabled: false,
},
},
},
Comment thread
LKuchno marked this conversation as resolved.
},
];

export function App() {
return <TabsContainerWithHostConfigContext routeConfigs={ROUTE_CONFIGS} />;
}

const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 18,
},
content: {
padding: 16,
},
section: {
marginBottom: 16,
},
heading: {
fontSize: 18,
fontWeight: '600',
color: Colors.OffNavy,
marginBottom: 8,
},
description: {
fontSize: 14,
color: Colors.LightOffNavy,
marginBottom: 8,
},
text: {
fontSize: 13,
color: Colors.LightOffNavy,
lineHeight: 20,
},
centeredContent: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
paddingHorizontal: 24,
gap: 12,
},
contentLabel: {
fontSize: 18,
fontWeight: '600',
color: Colors.OffNavy,
textAlign: 'center',
},
contentHint: {
fontSize: 13,
color: Colors.LightOffNavy,
textAlign: 'center',
lineHeight: 20,
},
});

export default createScenario(App, scenarioDescription);
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { ScenarioDescription } from '@apps/tests/shared/helpers';

export const scenarioDescription: ScenarioDescription = {
name: 'Native Container Style',
key: 'test-tabs-native-container-style',
details:
'Tests the nativeContainerStyle prop with backgroundColor variations on TabsHost.',
platforms: ['android', 'ios'],
e2eCoverage: 'incomplete',
smokeTest: false,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Test Scenario: nativeContainerStyle

## Details

**Description:** Verifies the `nativeContainerStyle` prop on `TabsHost`,
which allows customising the background color of the native container
wrapping the tabs. The test validates that setting `backgroundColor`
via the picker applies the color to the correct native surface on each
platform, that the color persists when switching between tabs, and that
restoring `unset` returns the container to the system default. The prop
is a host-level setting: it is not per-route.

**OS test creation version:** iOS: 18.6 and 26.5, Android: API Level 36.

## E2E test

Incomplete: Not automated. Detox cannot assert native background-color
attributes on either platform, so visual verification must be done
manually.

## Prerequisites

- iOS device or simulator
- Android emulator or device

## Note

- On iOS the color fills the area behind the content screen and around
the tab bar (the full `UITabBarController` view).
- On Android the color fills the `FrameLayout` that wraps currently focused
screen and the `BottomNavigationView`.
- On Android and iOS 18 and earlier, the tab bar may obscures the color unless
a transparent or semi-transparent background is configured.
- On iOS 26, while the "liquid glass" tab bar partially obscures the color, it
remains inherently visible through the material.

## Steps

### Baseline

1. Launch the app and navigate to **Native Container Style**.

- [ ] The **Config** tab is active. The `backgroundColor`
picker shows `unset`.
- [ ] The container background is the system default (no custom color visible).
- [ ] Tab bar background is red.
- [ ] **iOS 26:** The system default color is visible through the liquid glass tab bar.

---

### Setting backgroundColor to blue and yellow

2. On the **Config** tab, set the `backgroundColor` picker to `blue`.

- [ ] The picker displays `blue`. The native container's background changes to blue.
- [ ] The blue color is visible behind the tab content area.
- [ ] The tab bar retains red color.
- [ ] **iOS 26:** The blue color is visible through the liquid glass tab bar.

3. Tap the **Transparent** tab in the tab bar.

- [ ] The **Transparent** screen content is displayed (featuring the "Transparent Tab" label and
hint text).
- [ ] The container background remains blue.
- [ ] The tab bar is transparent, making the blue background visible behind the tabs.
- [ ] **iOS 26:** The appearance of the tab bar area is identical to the previous step.

4. Tap the **Config** tab to switch back.

- [ ] The **Config** tab is shown again.
- [ ] The blue container background persists.

5. Set the `backgroundColor` picker to `yellow`.

- [ ] The yellow color is visible behind the tab content area.
- [ ] The tab bar retains red color.
- [ ] **iOS 26:** The yellow color is visible through the liquid glass tab bar.

6. Tap the **Transparent** tab, observe the background, then return to **Config**.

- [ ] The container background remains yellow.
- [ ] The tab bar is transparent, making the yellow background visible behind the tabs.
- [ ] **iOS 26:** The appearance of the tab bar area is identical to the previous step.

---

### Restoring to unset

7. Return to **Config** and set the `backgroundColor` picker back to `unset`.

- [ ] The container background returns to the system default.
- [ ] The tab bar retains red color.
- [ ] **iOS 26:** The system default color is visible through the liquid glass tab bar.

8. Tap the **Transparent** tab and observe the background.

- [ ] The **Transparent** screen appears with the system-default container background.
- [ ] No color remnant from the previous `yellow` value is visible.

---

### Rapid color cycling (edge case)

9. From the **Config** tab, cycle the `backgroundColor` picker rapidly
through `blue` → `yellow` → `purple` → `unset` → `blue`.

- [ ] The container background updates with each selection.
- [ ] No crash, no layout freeze, and no color bleed between selections.
- [ ] The final displayed color is blue.
Loading