xref: /expo/docs/pages/routing/appearance.mdx (revision fa939da8)
1---
2title: Appearance elements
3description: Learn how to use a splash screen, fonts and images in your app that is using Expo Router.
4---
5
6import { BoxLink } from '~/ui/components/BoxLink';
7import { BookOpen02Icon } from '@expo/styleguide-icons';
8
9There are three major elements that you can use to customize the appearance of your app:
10
11- Fonts
12- Images
13- Splash screen
14
15## Fonts
16
17Expo Router extends the `expo-splash-screen` API to prevent white flash. Use it in conjunction with `expo-font` to keep the splash screen visible while fonts are loading:
18
19```js app/_layout.js
20import { Text, View } from 'react-native';
21import {
22  /* @info Import `SplashScreen` from `expo-router` instead of `expo-splash-screen` */
23  SplashScreen,
24  /* @end */
25  // This example uses a basic Layout component, but you can use any Layout.
26  Slot,
27} from 'expo-router';
28
29import { useFonts, Inter_500Medium } from '@expo-google-fonts/inter';
30
31/* @info Prevent hiding the splash screen after the navigation has mounted. */
32SplashScreen.preventAutoHideAsync();
33/* @end */
34
35export default function Layout() {
36  /* @info Load the font <b>Inter_500Medium</b> */
37  const [fontsLoaded, fontError] = useFonts({
38    /* @end */
39    Inter_500Medium,
40  });
41
42  useEffect(() => {
43    if (fontsLoaded || fontError) {
44      // Hide the splash screen after the fonts have loaded (or an error was returned) and the UI is ready.
45      SplashScreen.hideAsync();
46    }
47  }, [fontsLoaded, fontError]);
48
49  // Prevent rendering until the font has loaded or an error was returned
50  if (!fontsLoaded && !fontError) {
51    return null;
52  }
53
54  // Render the children routes now that all the assets are loaded.
55  return <Slot />;
56}
57```
58
59In SDK 50 and above, Expo Router's [static rendering](/router/reference/static-rendering) provides [automatic static optimization](/router/reference/static-rendering#fonts) for font loading on web. This enables best-practices for working with fonts in the browser.
60
61## Images
62
63We recommend you use Expo Image for the best cross-platform experience:
64
65<BoxLink
66  title="Expo Image API reference"
67  description="For more information on how to install and use expo-image, see its API documentation."
68  href="/versions/latest/sdk/image"
69  imageUrl="/static/images/packages/expo-image.png"
70/>
71
72## Splash screen
73
74Splash screens are required on native platforms. Expo Router automatically orchestrates the native splash screen to keep it visible until the first route is rendered, this applies to any route that the user deep links into. To enable this functionality, install expo-splash-screen in your project.
75
76The default behavior is to hide the splash screen when the first route is rendered, this is optimal for the majority of routes. For some routes, you may want to prolong the splash screen until additional data or asset loading has concluded. This can be achieved with the `SplashScreen` module from `expo-router`. If `SplashScreen.preventAutoHideAsync` is called before the splash screen is hidden, then the splash screen will remain visible until the `SplashScreen.hideAsync()` function has been invoked.
77
78```js app/index.tsx
79import { SplashScreen } from 'expo-router';
80
81/* @info Prevent hiding the splash screen after the navigation has mounted. */
82SplashScreen.preventAutoHideAsync();
83/* @end */
84
85export default function App() {
86  const [isReady, setReady] = React.useState(false);
87  React.useEffect(() => {
88    // Perform some sort of async data or asset fetching.
89    setTimeout(() => {
90      // When all loading is setup, unmount the splash screen component.
91      SplashScreen.hideAsync();
92      setReady(true);
93    }, 1000);
94  }, []);
95
96  return <Text>My App</Text>;
97}
98```
99
100## React Navigation themes
101
102React Navigation navigators `<Stack>`, `<Drawer>`, and `<Tabs>` use a shared appearance provider. In React Navigation, you set the theme for the entire app using the `<NavigationContainer />` component. Expo Router manages the root container so that you can set the theme using the `ThemeProvider` directly.
103
104```tsx app/_layout.tsx
105/* @info Import theme APIs from React Navigation directly. */
106import { ThemeProvider, DarkTheme, DefaultTheme, useTheme } from '@react-navigation/native';
107/* @end */
108
109import { Slot } from 'expo-router';
110
111export default function RootLayout() {
112  return (
113    /* @info All layouts inside this provider will use the dark theme. */
114    <ThemeProvider value={DarkTheme}>
115      /* @end */
116      <Slot />
117    </ThemeProvider>
118  );
119}
120```
121
122You can use this technique at any layer of the app to set the theme for a specific layout. The current theme can be accessed with `useTheme` from `@react-navigation/native`.
123
124## Next steps
125
126<BoxLink
127  title="Error handling"
128  description="Improve the user experience by gracefully handling unexpected errors."
129  href="/routing/error-handling/"
130  Icon={BookOpen02Icon}
131/>
132