React Native course ยท Module 2: Lists and styles
StatusBar and Theming
In this lesson2
Control the appearance of the status bar and create a theme system for your application.
StatusBar
import { SafeAreaView, View, Text, StyleSheet, StatusBar, Pressable } from 'react-native';
import { useState } from 'react';
export default function StatusBarExample() {
const [isDark, setIsDark] = useState(true);
return (
<SafeAreaView style={[
styles.container,
{ backgroundColor: isDark ? '#1a5276' : '#ecf0f1' }
]}>
<StatusBar
barStyle={isDark ? 'light-content' : 'dark-content'}
backgroundColor={isDark ? '#1a5276' : '#ecf0f1'}
animated={true}
/>
<View style={styles.content}>
<Text style={[styles.title, { color: isDark ? '#fff' : '#2c3e50' }]}>
Status Bar Demo
</Text>
<Pressable
style={[styles.button, { backgroundColor: isDark ? '#2980b9' : '#3498db' }]}
onPress={() => setIsDark(!isDark)}
>
<Text style={styles.buttonText}>
Switch to {isDark ? 'light' : 'dark'} theme
</Text>
</Pressable>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
content: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
title: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 30,
},
button: {
paddingVertical: 14,
paddingHorizontal: 24,
borderRadius: 8,
},
buttonText: {
color: '#fff',
fontSize: 16,
fontWeight: '600',
},
});Theme System with Context
// context/ThemeContext.tsx
import { createContext, useContext, useState, ReactNode } from 'react';
interface Theme {
dark: boolean;
colors: {
background: string;
card: string;
text: string;
textSecondary: string;
primary: string;
border: string;
};
}
const lightTheme: Theme = {
dark: false,
colors: {
background: '#f5f6fa',
card: '#ffffff',
text: '#2c3e50',
textSecondary: '#7f8c8d',
primary: '#3498db',
border: '#dcdde1',
},
};
const darkTheme: Theme = {
dark: true,
colors: {
background: '#1a5276',
card: '#2c3e50',
text: '#ffffff',
textSecondary: '#bdc3c7',
primary: '#3498db',
border: '#34495e',
},
};
interface ThemeContextType {
theme: Theme;
toggleTheme: () => void;
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
export function ThemeProvider({ children }: { children: ReactNode }) {
const [isDark, setIsDark] = useState(true);
const theme = isDark ? darkTheme : lightTheme;
const toggleTheme = () => setIsDark(!isDark);
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme must be used within ThemeProvider');
}
return context;
}// components/ThemedCard.tsx
import { View, Text, StyleSheet } from 'react-native';
import { useTheme } from '../context/ThemeContext';
interface ThemedCardProps {
title: string;
description: string;
}
export default function ThemedCard({ title, description }: ThemedCardProps) {
const { theme } = useTheme();
return (
<View style={[styles.card, { backgroundColor: theme.colors.card }]}>
<Text style={[styles.title, { color: theme.colors.text }]}>
{title}
</Text>
<Text style={[styles.description, { color: theme.colors.textSecondary }]}>
{description}
</Text>
</View>
);
}
const styles = StyleSheet.create({
card: {
padding: 16,
borderRadius: 12,
marginBottom: 12,
},
title: {
fontSize: 18,
fontWeight: '600',
marginBottom: 4,
},
description: {
fontSize: 14,
},
});// App.tsx
import { SafeAreaView, View, StyleSheet, StatusBar, Pressable, Text } from 'react-native';
import { ThemeProvider, useTheme } from './context/ThemeContext';
import ThemedCard from './components/ThemedCard';
function HomeScreen() {
const { theme, toggleTheme } = useTheme();
return (
<SafeAreaView style={[styles.container, { backgroundColor: theme.colors.background }]}>
<StatusBar barStyle={theme.dark ? 'light-content' : 'dark-content'} />
<View style={styles.content}>
<ThemedCard
title="Treasure of Atlantis"
description="A legendary jewel from the ocean depths"
/>
<ThemedCard
title="Poseidon's Trident"
description="Weapon of the ruler of the seas"
/>
<Pressable
style={[styles.button, { backgroundColor: theme.colors.primary }]}
onPress={toggleTheme}
>
<Text style={styles.buttonText}>
{theme.dark ? 'Light theme' : 'Dark theme'}
</Text>
</Pressable>
</View>
</SafeAreaView>
);
}
export default function App() {
return (
<ThemeProvider>
<HomeScreen />
</ThemeProvider>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
content: {
flex: 1,
padding: 20,
},
button: {
marginTop: 20,
paddingVertical: 14,
borderRadius: 8,
alignItems: 'center',
},
buttonText: {
color: '#fff',
fontSize: 16,
fontWeight: '600',
},
});Congratulations! You have mastered advanced components and styling in React Native!
Code for this lesson: App.tsx
import React, { createContext, useContext, useState, ReactNode } from 'react';
import { SafeAreaView, View, Text, Pressable, StyleSheet } from 'react-native';
const lightTheme = {
dark: false,
background: '#f5f6fa',
card: '#ffffff',
text: '#2c3e50',
};
const darkTheme = {
dark: true,
background: '#1a5276',
card: '#2c3e50',
text: '#ffffff',
};
const ThemeContext = createContext({ theme: darkTheme, toggleTheme: () => {} });
function ThemeProvider({ children }: { children: ReactNode }) {
const [isDark, setIsDark] = useState(true);
// TODO: pick the theme based on the isDark state.
// const theme = isDark ? darkTheme : lightTheme;
const theme = darkTheme;
// TODO: create a toggleTheme function that flips isDark.
// const toggleTheme = () => setIsDark(!isDark);
const toggleTheme = () => {};
// TODO: pass { theme, toggleTheme } to the Provider's value prop.
return (
<ThemeContext.Provider value={{ theme: darkTheme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
function HomeScreen() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<SafeAreaView style={[styles.container, { backgroundColor: theme.background }]}>
<View style={[styles.card, { backgroundColor: theme.card }]}>
<Text style={[styles.text, { color: theme.text }]}>Treasure of Atlantis</Text>
</View>
<Pressable style={styles.button} onPress={toggleTheme}>
<Text style={styles.buttonText}>
{theme.dark ? 'Light theme' : 'Dark theme'}
</Text>
</Pressable>
</SafeAreaView>
);
}
export default function App() {
return (
<ThemeProvider>
<HomeScreen />
</ThemeProvider>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
card: {
padding: 16,
borderRadius: 12,
marginBottom: 20,
},
text: {
fontSize: 18,
fontWeight: '600',
},
button: {
paddingVertical: 14,
borderRadius: 8,
alignItems: 'center',
backgroundColor: '#3498db',
},
buttonText: {
color: '#fff',
fontSize: 16,
fontWeight: '600',
},
});Docs entries used in this lesson
Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. Which StatusBar barStyle value shows light icons (for a dark background)?
2. What does the useColorScheme() hook return?
Hands-on tasks in the game
- Vertical ordering
Arrange the steps of creating a theme system with Context API:
- Code editor
Complete the ThemeProvider and ThemeContext code.