or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

deep-linking.mdindex.mdlink-components.mdnavigation-container.mdnavigation-hooks.mdserver-side-rendering.mdstatic-navigation.mdtheming.md

theming.mddocs/

0

# Theming

1

2

React Navigation's theming system provides built-in light and dark themes with full customization support. Themes control colors, fonts, and visual styling across all navigation components.

3

4

## Capabilities

5

6

### Built-in Themes

7

8

Pre-configured light and dark themes that follow platform design guidelines.

9

10

```typescript { .api }

11

/** Default light theme following iOS design guidelines */

12

const DefaultTheme: Theme;

13

14

/** Default dark theme following iOS design guidelines */

15

const DarkTheme: Theme;

16

17

interface Theme {

18

/** Whether this is a dark theme */

19

dark: boolean;

20

/** Color palette for navigation components */

21

colors: {

22

/** Primary color for active elements */

23

primary: string;

24

/** Background color for screens */

25

background: string;

26

/** Background color for cards and surfaces */

27

card: string;

28

/** Primary text color */

29

text: string;

30

/** Border and separator color */

31

border: string;

32

/** Color for notifications and badges */

33

notification: string;

34

};

35

/** Font configurations for different text weights */

36

fonts: {

37

regular: FontStyle;

38

medium: FontStyle;

39

bold: FontStyle;

40

heavy: FontStyle;

41

};

42

}

43

44

interface FontStyle {

45

/** Font family name */

46

fontFamily: string;

47

/** Font weight specification */

48

fontWeight: 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900';

49

}

50

```

51

52

**Usage Examples:**

53

54

```typescript

55

import { NavigationContainer, DefaultTheme, DarkTheme } from '@react-navigation/native';

56

import { useColorScheme } from 'react-native';

57

58

// Automatic theme switching based on device settings

59

function App() {

60

const scheme = useColorScheme();

61

62

return (

63

<NavigationContainer theme={scheme === 'dark' ? DarkTheme : DefaultTheme}>

64

{/* Your navigation structure */}

65

</NavigationContainer>

66

);

67

}

68

69

// Always use light theme

70

function LightApp() {

71

return (

72

<NavigationContainer theme={DefaultTheme}>

73

{/* Your navigation structure */}

74

</NavigationContainer>

75

);

76

}

77

78

// Always use dark theme

79

function DarkApp() {

80

return (

81

<NavigationContainer theme={DarkTheme}>

82

{/* Your navigation structure */}

83

</NavigationContainer>

84

);

85

}

86

```

87

88

### Custom Themes

89

90

Create custom themes by extending or completely replacing the built-in themes.

91

92

```typescript { .api }

93

// Custom theme creation patterns

94

type CustomTheme = Theme;

95

96

// Theme color values for DefaultTheme

97

const DefaultThemeColors = {

98

primary: 'rgb(0, 122, 255)',

99

background: 'rgb(242, 242, 242)',

100

card: 'rgb(255, 255, 255)',

101

text: 'rgb(28, 28, 30)',

102

border: 'rgb(216, 216, 216)',

103

notification: 'rgb(255, 59, 48)',

104

};

105

106

// Theme color values for DarkTheme

107

const DarkThemeColors = {

108

primary: 'rgb(10, 132, 255)',

109

background: 'rgb(1, 1, 1)',

110

card: 'rgb(18, 18, 18)',

111

text: 'rgb(229, 229, 231)',

112

border: 'rgb(39, 39, 41)',

113

notification: 'rgb(255, 69, 58)',

114

};

115

```

116

117

**Custom Theme Examples:**

118

119

```typescript

120

// Extend existing theme

121

const CustomLightTheme = {

122

...DefaultTheme,

123

colors: {

124

...DefaultTheme.colors,

125

primary: '#007AFF',

126

notification: '#FF3B30',

127

},

128

};

129

130

// Brand-specific theme

131

const BrandTheme = {

132

...DefaultTheme,

133

colors: {

134

...DefaultTheme.colors,

135

primary: '#6366f1', // Indigo

136

background: '#f8fafc', // Slate 50

137

card: '#ffffff',

138

text: '#0f172a', // Slate 900

139

border: '#e2e8f0', // Slate 200

140

notification: '#ef4444', // Red 500

141

},

142

};

143

144

// Complete custom theme

145

const FullCustomTheme: Theme = {

146

dark: false,

147

colors: {

148

primary: '#8b5cf6', // Purple

149

background: '#faf5ff', // Purple 50

150

card: '#ffffff',

151

text: '#581c87', // Purple 900

152

border: '#c4b5fd', // Purple 300

153

notification: '#f59e0b', // Amber 500

154

},

155

fonts: {

156

regular: {

157

fontFamily: 'Inter-Regular',

158

fontWeight: '400',

159

},

160

medium: {

161

fontFamily: 'Inter-Medium',

162

fontWeight: '500',

163

},

164

bold: {

165

fontFamily: 'Inter-Bold',

166

fontWeight: '700',

167

},

168

heavy: {

169

fontFamily: 'Inter-Black',

170

fontWeight: '900',

171

},

172

},

173

};

174

175

// Dynamic theme based on user preferences

176

function AppWithDynamicTheme() {

177

const [themeMode, setThemeMode] = useState<'light' | 'dark' | 'brand'>('light');

178

179

const getTheme = () => {

180

switch (themeMode) {

181

case 'dark':

182

return DarkTheme;

183

case 'brand':

184

return BrandTheme;

185

default:

186

return DefaultTheme;

187

}

188

};

189

190

return (

191

<NavigationContainer theme={getTheme()}>

192

{/* Your navigation structure */}

193

</NavigationContainer>

194

);

195

}

196

```

197

198

### Font Configuration

199

200

Customize font families and weights for different text elements.

201

202

```typescript { .api }

203

interface FontStyle {

204

/** Font family name - should match fonts available in your app */

205

fontFamily: string;

206

/** CSS-style font weight specification */

207

fontWeight: 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900';

208

}

209

210

// Default font configuration

211

const defaultFonts = {

212

regular: {

213

fontFamily: 'System',

214

fontWeight: 'normal' as const,

215

},

216

medium: {

217

fontFamily: 'System',

218

fontWeight: '500' as const,

219

},

220

bold: {

221

fontFamily: 'System',

222

fontWeight: '600' as const,

223

},

224

heavy: {

225

fontFamily: 'System',

226

fontWeight: '700' as const,

227

},

228

};

229

```

230

231

**Font Customization Examples:**

232

233

```typescript

234

// Custom font theme

235

const CustomFontTheme = {

236

...DefaultTheme,

237

fonts: {

238

regular: {

239

fontFamily: 'Roboto-Regular',

240

fontWeight: '400',

241

},

242

medium: {

243

fontFamily: 'Roboto-Medium',

244

fontWeight: '500',

245

},

246

bold: {

247

fontFamily: 'Roboto-Bold',

248

fontWeight: '700',

249

},

250

heavy: {

251

fontFamily: 'Roboto-Black',

252

fontWeight: '900',

253

},

254

},

255

};

256

257

// Mixed font families

258

const MixedFontTheme = {

259

...DefaultTheme,

260

fonts: {

261

regular: {

262

fontFamily: 'Inter-Regular',

263

fontWeight: '400',

264

},

265

medium: {

266

fontFamily: 'Inter-Medium',

267

fontWeight: '500',

268

},

269

bold: {

270

fontFamily: 'Poppins-SemiBold', // Different font for bold

271

fontWeight: '600',

272

},

273

heavy: {

274

fontFamily: 'Poppins-Bold',

275

fontWeight: '700',

276

},

277

},

278

};

279

280

// Platform-specific fonts

281

const PlatformFontTheme = {

282

...DefaultTheme,

283

fonts: {

284

regular: {

285

fontFamily: Platform.select({

286

ios: 'San Francisco',

287

android: 'Roboto',

288

default: 'System',

289

}),

290

fontWeight: '400',

291

},

292

medium: {

293

fontFamily: Platform.select({

294

ios: 'San Francisco',

295

android: 'Roboto',

296

default: 'System',

297

}),

298

fontWeight: '500',

299

},

300

bold: {

301

fontFamily: Platform.select({

302

ios: 'San Francisco',

303

android: 'Roboto',

304

default: 'System',

305

}),

306

fontWeight: '600',

307

},

308

heavy: {

309

fontFamily: Platform.select({

310

ios: 'San Francisco',

311

android: 'Roboto',

312

default: 'System',

313

}),

314

fontWeight: '700',

315

},

316

},

317

};

318

```

319

320

### Theme Usage in Components

321

322

Access theme values in your components using React Navigation's theming hooks.

323

324

```typescript { .api }

325

// Theme access is provided by @react-navigation/core

326

import { useTheme } from '@react-navigation/core';

327

328

function useTheme(): Theme;

329

```

330

331

**Component Usage Examples:**

332

333

```typescript

334

import { useTheme } from '@react-navigation/native';

335

import { View, Text, StyleSheet } from 'react-native';

336

337

// Basic theme usage

338

function ThemedComponent() {

339

const { colors, fonts } = useTheme();

340

341

return (

342

<View style={[styles.container, { backgroundColor: colors.card }]}>

343

<Text style={[fonts.bold, { color: colors.text }]}>

344

Themed Text

345

</Text>

346

</View>

347

);

348

}

349

350

// Dynamic styling based on theme

351

function AdaptiveComponent({ children }) {

352

const { colors, dark } = useTheme();

353

354

return (

355

<View style={[

356

styles.container,

357

{

358

backgroundColor: colors.card,

359

borderColor: colors.border,

360

shadowColor: dark ? colors.border : '#000',

361

shadowOpacity: dark ? 0.3 : 0.1,

362

}

363

]}>

364

{children}

365

</View>

366

);

367

}

368

369

// Theme-aware button

370

function ThemedButton({ title, onPress, variant = 'primary' }) {

371

const { colors, fonts } = useTheme();

372

373

const getButtonStyle = () => {

374

switch (variant) {

375

case 'primary':

376

return {

377

backgroundColor: colors.primary,

378

borderColor: colors.primary,

379

};

380

case 'secondary':

381

return {

382

backgroundColor: 'transparent',

383

borderColor: colors.border,

384

};

385

default:

386

return {

387

backgroundColor: colors.card,

388

borderColor: colors.border,

389

};

390

}

391

};

392

393

const getTextStyle = () => {

394

switch (variant) {

395

case 'primary':

396

return { color: '#fff' };

397

default:

398

return { color: colors.text };

399

}

400

};

401

402

return (

403

<TouchableOpacity

404

style={[styles.button, getButtonStyle()]}

405

onPress={onPress}

406

>

407

<Text style={[fonts.medium, getTextStyle()]}>

408

{title}

409

</Text>

410

</TouchableOpacity>

411

);

412

}

413

414

const styles = StyleSheet.create({

415

container: {

416

padding: 16,

417

borderWidth: 1,

418

borderRadius: 8,

419

},

420

button: {

421

paddingVertical: 12,

422

paddingHorizontal: 24,

423

borderRadius: 6,

424

borderWidth: 1,

425

alignItems: 'center',

426

},

427

});

428

```

429

430

### Theme Persistence

431

432

Save and restore user theme preferences across app sessions.

433

434

```typescript { .api }

435

// Theme persistence patterns

436

interface ThemePreference {

437

mode: 'light' | 'dark' | 'system';

438

customColors?: Partial<Theme['colors']>;

439

}

440

```

441

442

**Persistence Examples:**

443

444

```typescript

445

import AsyncStorage from '@react-native-async-storage/async-storage';

446

447

// Theme context for app-wide theme management

448

const ThemeContext = createContext<{

449

theme: Theme;

450

themeMode: 'light' | 'dark' | 'system';

451

setThemeMode: (mode: 'light' | 'dark' | 'system') => void;

452

}>({

453

theme: DefaultTheme,

454

themeMode: 'system',

455

setThemeMode: () => {},

456

});

457

458

// Theme provider with persistence

459

function ThemeProvider({ children }) {

460

const systemColorScheme = useColorScheme();

461

const [themeMode, setThemeMode] = useState<'light' | 'dark' | 'system'>('system');

462

463

// Load saved theme preference

464

useEffect(() => {

465

const loadTheme = async () => {

466

try {

467

const savedTheme = await AsyncStorage.getItem('theme-mode');

468

if (savedTheme) {

469

setThemeMode(savedTheme as 'light' | 'dark' | 'system');

470

}

471

} catch (error) {

472

console.error('Failed to load theme preference:', error);

473

}

474

};

475

476

loadTheme();

477

}, []);

478

479

// Save theme preference when changed

480

const handleThemeChange = async (mode: 'light' | 'dark' | 'system') => {

481

try {

482

await AsyncStorage.setItem('theme-mode', mode);

483

setThemeMode(mode);

484

} catch (error) {

485

console.error('Failed to save theme preference:', error);

486

}

487

};

488

489

// Determine active theme

490

const getActiveTheme = (): Theme => {

491

switch (themeMode) {

492

case 'dark':

493

return DarkTheme;

494

case 'light':

495

return DefaultTheme;

496

case 'system':

497

return systemColorScheme === 'dark' ? DarkTheme : DefaultTheme;

498

default:

499

return DefaultTheme;

500

}

501

};

502

503

const theme = getActiveTheme();

504

505

return (

506

<ThemeContext.Provider value={{

507

theme,

508

themeMode,

509

setThemeMode: handleThemeChange,

510

}}>

511

<NavigationContainer theme={theme}>

512

{children}

513

</NavigationContainer>

514

</ThemeContext.Provider>

515

);

516

}

517

518

// Theme settings screen

519

function ThemeSettingsScreen() {

520

const { themeMode, setThemeMode } = useContext(ThemeContext);

521

522

return (

523

<View>

524

<Text>Theme Settings</Text>

525

<Button

526

title="Light"

527

onPress={() => setThemeMode('light')}

528

disabled={themeMode === 'light'}

529

/>

530

<Button

531

title="Dark"

532

onPress={() => setThemeMode('dark')}

533

disabled={themeMode === 'dark'}

534

/>

535

<Button

536

title="System"

537

onPress={() => setThemeMode('system')}

538

disabled={themeMode === 'system'}

539

/>

540

</View>

541

);

542

}

543

```