# Expo Documentation Expo is an open-source React Native framework for apps that run natively on Android, iOS, and the web. Expo brings together the best of mobile and the web and enables many important features for building and scaling an app such as live updates, instantly sharing your app, and web support. The company behind Expo also offers Expo Application Services (EAS), which are deeply integrated cloud services for Expo and React Native apps. # Get started ## Introduction Get started creating apps with Expo. Expo is a framework that makes developing Android and iOS apps easier. Our framework provides file-based routing, a standard library of native modules, and much more. Expo is open source with an active community on [GitHub](https://github.com/expo/expo) and [Discord](https://chat.expo.dev). We also make [Expo Application Services (EAS)](https://expo.dev/eas), a set of services that complement the Expo framework in each step of the development process. There are two ways to get started: ## Create a project Learn how to create a new Expo project. System requirements: - [Node.js (LTS)](https://nodejs.org/en/). - macOS, Windows (Powershell and [WSL 2](https://expo.fyi/wsl)), and Linux are supported. We recommend starting with the default project created by `create-expo-app`. The default project includes example code to help you get started. To create a new project, run the following command: ```sh $ npx create-expo-app@latest ``` > You can choose a different template by adding the [`--template` option](/more/create-expo/#--template). ## Next step You have a project. Now it's time to set up your development environment so that you can start developing. ## Set up your environment Learn how to set up your development environment to start building with Expo. Let's set up a local development environment for running your project on Android and iOS. ## Where would you like to develop? We recommend using a real device to develop, since you'll get to see exactly what your users will see. ## How would you like to develop? Expo Go is a sandbox for trying out Expo quickly. A development build is a build of your own app that includes Expo's developer tools. --- # Android Emulator Setup ## Set up an emulator Step 1: On the Android Studio main screen, click **More Actions**, then **Virtual Device Manager** in the dropdown. Step 2: Click the **Create device** button. Step 3: Under **Select Hardware**, choose the type of hardware you'd like to emulate. We recommend testing against a variety of devices, but if you're unsure where to start, the newest device in the Pixel line could be a good choice. Step 4: Select an OS version to load on the emulator (probably one of the system images in the **Recommended** tab), and download the image. Step 5: Change any other settings you'd like, and press **Finish** to create the emulator. You can now run this emulator anytime by pressing the Play button in the AVD Manager window. # Android Studio Environment Setup ## Install Watchman and JDK #### Prerequisites Use a package manager such as [Homebrew](https://brew.sh/) to install the following dependency. #### Install dependencies Step 1: [Install Watchman](https://facebook.github.io/watchman/docs/install#macos) using a tool such as Homebrew: ```sh $ brew install watchman ``` Step 2: Install OpenJDK distribution called Azul Zulu using Homebrew. This distribution offers JDKs for both Apple Silicon and Intel Macs. Run the following commands in a terminal: ```sh $ brew install --cask zulu@17 ``` After you install the JDK, add the `JAVA_HOME` environment variable in **~/.bash_profile** (or **~/.zshrc** if you use Zsh): ```bash export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home ``` #### Prerequisites Use a package manager such as [Chocolatey](https://chocolatey.org/) to install the following dependencies. #### Install dependencies Install [Java SE Development Kit (JDK)](https://openjdk.org/): ```sh $ choco install -y microsoft-openjdk17 ``` For Linux: #### Install dependencies Step 1: Follow [instructions from the Watchman documentation](https://facebook.github.io/watchman/docs/install#linux) to compile and install it from the source. Step 2: Install [Java SE Development Kit (JDK)](https://openjdk.org/): You can download and install [OpenJDK](http://openjdk.java.net/) from [AdoptOpenJDK](https://adoptopenjdk.net/) or your system packager. # Android Studio Setup ## Set up Android Studio For macOS: Step 1: Download and install [Android Studio](https://developer.android.com/studio). Step 2: Open the **Android Studio** app, click **More Actions** and select **SDK Manager**. Step 3: Open Android Studio, go to **Settings** > **Languages & Frameworks** > **Android SDK**. From the **SDK Platforms** tab, select the latest Android version (API level). Then, click on the **SDK Tools** tab and make sure you have at least one version of the **Android SDK Build-Tools** and **Android Emulator** installed. Step 4: Copy or remember the path listed in the box that says **Android SDK Location**. Step 5: Click **Apply** and **OK** to install the Android SDK and related build tools. Step 6: If you are on macOS or Linux, add an [environment variable](https://developer.android.com/studio/command-line/variables#envar) pointing to the Android SDK location in **~/.bash_profile** (or **~/.zshrc** if you use Zsh). For example: `export ANDROID_HOME=/your/path/here`. Add the following lines to your **/.zprofile** or **~/.zshrc** (if you are using bash, then **~/.bash_profile** or **~/.bashrc**) config file: ```sh $ export ANDROID_HOME=$HOME/Library/Android/sdk $ export PATH=$PATH:$ANDROID_HOME/emulator $ export PATH=$PATH:$ANDROID_HOME/platform-tools ``` Step 7: Reload the path environment variables in your current shell: ```sh $ source $HOME/.zshrc $ source $HOME/.bashrc ``` Step 8: Finally, make sure that you can run `adb` from your terminal. For Windows: Step 1: Download [Android Studio](https://developer.android.com/studio). Step 2: Open **Android Studio Setup**. Under **Select components to install**, select Android Studio and Android Virtual Device. Then, click **Next**. Step 3: In the Android Studio Setup Wizard, under **Install Type**, select **Standard** and click **Next**. Step 4: The Android Studio Setup Wizard will ask you to verify the settings, such as the version of Android SDK, platform-tools, and so on. Click **Next** after you have verified. Step 5: In the next window, accept licenses for all available components. Step 6: After the tools installation is complete, configure the `ANDROID_HOME` environment variable. Go to **Windows Control Panel** > **User Accounts** > **User Accounts** (again) > **Change my environment variables** and click **New** to create a new `ANDROID_HOME` user variable. The value of this variable will point to the path to your Android SDK: Note: How to find installed SDK location? --- By default, the Android SDK is installed at the following location: ```bash %LOCALAPPDATA%\Android\Sdk ``` To find the location of the SDK in Android Studio manually, go to **Settings** > **Languages & Frameworks** > **Android SDK**. See the location next to **Android SDK Location**. --- Step 7: To verify that the new environment variable is loaded, open **PowerShell**, and copy and paste the following command: ```sh $ Get-ChildItem -Path Env: ``` The command will output all user environment variables. In this list, see if `ANDROID_HOME` has been added. Step 8: To add platform-tools to the Path, go to **Windows Control Panel** > **User Accounts** > **User Accounts** (again) > **Change my environment variables** > **Path** > **Edit** > **New** and add the path to the platform-tools to the list as shown below: Note: How to find installed platform-tools location --- By default, the platform-tools are installed at the following location: ```bash %LOCALAPPDATA%\Android\Sdk\platform-tools ``` --- Step 9: Finally, make sure that you can run `adb` from the PowerShell. For example, run the `adb --version` to see which version of the `adb` your system is running. # Xcode Setup Step 1: ### Install Xcode Open up the Mac App Store, search for [Xcode](https://apps.apple.com/us/app/xcode/id497799835), and click **Install** (or **Update** if you have it already). Step 2: ### Install Xcode Command Line Tools Open Xcode, choose **Settings...** from the Xcode menu (or press cmd ⌘ + ,). Go to the **Locations** and install the tools by selecting the most recent version in the **Command Line Tools** dropdown. Step 3: ### Install Watchman [Watchman](https://facebook.github.io/watchman/docs/install#macos) is a tool for watching changes in the filesystem. Installing it will result in better performance. You can install it with: ```sh $ brew update $ brew install watchman ``` # Create a development build for a physical Android device with EAS ## Set up an Android device with a development build Step 1: ### Install EAS CLI To build your app, you will need to install EAS CLI. You can do this by running the following command in your terminal: ```sh $ npm install -g eas-cli ``` Step 2: ### Create an Expo account and login To build your app, you will need to create an Expo account and login to the EAS CLI. 1. [Sign up](https://expo.dev/signup) for an Expo account. 2. Run the following command in your terminal to log in to the EAS CLI: ```sh $ eas login ``` Step 3: ### Configure your project Run the following command to create an EAS config in your project: ```sh $ eas build:configure ``` Step 4: ### Create a build Run the following command to create a development build: ```sh $ eas build --platform android --profile development ``` Step 5: ### Install the development build on your device After the build is complete, scan the QR code in your terminal or open the link on your device. Tap **Install** to download the build on your device, then tap **Open** to install it. # Create a development build for a physical Android device locally ## Set up an Android device with a development build ## Running your app on an Android device Step 1: ### Install expo-dev-client Run the following command in your project's root directory: ```sh $ npx expo install expo-dev-client ``` Step 2: ### Enable debugging over USB Most Android devices can only install and run apps downloaded from Google Play, by default. You will need to enable USB Debugging on your device to install your app during development. To enable USB debugging on your device, you will first need to enable the "Developer options" menu by going to **Settings** > **About phone** > **Software information** and then tapping the `Build number` row at the bottom seven times. You can then go back to **Settings** > **Developer options** to enable "USB debugging". Step 3: ### Plug in your device via USB Plug in your Android device via USB to your computer. Check that your device is properly connecting to ADB, the Android Debug Bridge, by running `adb devices` in your terminal. You should see your device listed with `device` listed next to it. For example: ```sh $ adb devices List of devices attached 8AHX0T32K device ``` Step 4: ### Run your app Run the following from your terminal: ```sh $ npx expo run:android ``` > This command runs a development server after building your app. You can skip running `npx expo start` on the next page. # Run on a physical Android device with Expo Go ## Set up an Android device with Expo Go Scan the QR code to download the app from the Google Play Store, or visit the Expo Go page on the [Google Play Store](https://play.google.com/store/apps/details?id=host.exp.exponent&referrer=docs).
# Create a development build for Android Emulator with EAS ## Set up an Android Emulator with a development build ## Create a development build Step 1: ### Install EAS CLI To build your app, you will need to install EAS CLI. You can do this by running the following command in your terminal: ```sh $ npm install -g eas-cli ``` Step 2: ### Create an Expo account and login To build your app, you will need to create an Expo account and login to the EAS CLI. 1. [Sign up](https://expo.dev/signup) for an Expo account. 2. Run the following command in your terminal to log in to the EAS CLI: ```sh $ eas login ``` Step 3: ### Configure your project Run the following command to create an EAS config in your project: ```sh $ eas build:configure ``` Step 4: ### Create a build Run the following command to create a development build: ```sh $ eas build --platform android --profile development ``` Step 5: ### Install the development build on your emulator After the build is complete, the CLI will prompt you to automatically download and install it on the Android Emulator. When prompted, press Y to directly install it on the emulator. If you miss this prompt, you can download the build from the link provided in the terminal and drag and drop it onto the Android Emulator to install it. # Create a development build for Android Emulator locally ## Set up an Android Emulator with a development build ## Running your app on an Android Emulator Step 1: ### Install expo-dev-client Run the following command in your project's root directory: ```sh $ npx expo install expo-dev-client ``` Step 2: Run the following from your terminal: ```sh $ npx expo run:android ``` > This command runs a development server after building your app. You can skip running `npx expo start` on the next page. # Run on Android Emulator with Expo Go ## Set up an Android Emulator with Expo Go ## Install Expo Go When you start a development server with `npx expo start` on the [start developing](/get-started/start-developing) page, press a to open the Android Emulator. Expo CLI will install Expo Go automatically. # Create a development build for a physical iOS device with EAS ## Set up an iOS device with a development build Step 1: ### Enroll in the Apple Developer Program To install a development build on your iOS device, you will need an active subscription to the Apple Developer Program. Sign up for the [Apple Developer Program here](https://developer.apple.com/programs/). Step 2: ### Install EAS CLI To build your app, you will need to install EAS CLI. You can do this by running the following command in your terminal: ```sh $ npm install -g eas-cli ``` Step 3: ### Create an Expo account and login Next, you will need to create an Expo account and login to the EAS CLI. 1. [Sign up](https://expo.dev/signup) for an Expo account. 2. Run the following command in your terminal to log in to the EAS CLI: ```sh $ eas login ``` Step 4: ### Configure your project Run the following command to create an EAS config in your project: ```sh $ eas build:configure ``` Step 5: ### Create an ad hoc provisioning profile To install a development build on your iOS device, you will need to create an ad hoc provisioning profile. Create one by running the following command in your terminal: ```sh $ eas device:create ``` Step 6: ### Create a development build Run the following command to create a development build: ```sh $ eas build --platform ios --profile development ``` Step 7: ### Turn on developer mode 1. Open **Settings** > **Privacy & Security**, scroll down to the **Developer Mode** list item and navigate into it. 2. Tap the switch to enable **Developer Mode**. After you do so, Settings presents an alert to warn you that Developer Mode reduces your device's security. To continue enabling **Developer Mode**, tap the alert's **Restart** button. 3. After the device restarts and you unlock it, the device shows an alert confirming that you want to enable Developer Mode. Tap **Turn On**, and enter your device passcode when prompted. > Alternatively, if you have Xcode installed on your Mac, you can use it to [enable iOS developer mode](/guides/ios-developer-mode/#connect-an-ios-device-with-a-mac). Step 8: ### Install the development build on your device After the build is complete, scan the QR code in your terminal and tap **Open with iTunes** when it appears inside the Camera app. Alternatively, open the link displayed in the terminal on your device. After confirming the installation, the app will appear in your device's app library. # Create a development build for a physical iOS device locally ## Set up an iOS device with a development build ## Set up Xcode and Watchman ## Configure your project Step 1: ### Install expo-dev-client Run the following command in your project's root directory: ```sh $ npx expo install expo-dev-client ``` Step 2: ### Plug in your device via USB and enable developer mode 1. Connect your iOS device to your Mac using a USB to Lightning cable. Unlock the device and tap **Trust** if prompted. 2. Open Xcode. From the menu bar, select **Window** > **Devices and Simulators**. You will see a warning in Xcode to enable developer mode. 3. On your iOS device, open **Settings** > **Privacy & Security**, scroll down to the **Developer Mode** list item and navigate into it. 4. Tap the switch to enable **Developer Mode**. After you do so, Settings presents an alert to warn you that Developer Mode reduces your device's security. To continue enabling **Developer Mode**, tap the alert's **Restart** button. 5. After the device restarts and you unlock it, the device shows an alert confirming that you want to enable Developer Mode. Tap **Turn On**, and enter your device passcode when prompted. Step 3: ### Run the project on your device Run the following command in your project's root directory and select your plugged in device from the list: ```sh $ npx expo run:ios --device ``` > This command runs a development server after building your app. You can skip running `npx expo start` on the next page. # Run on a physical iOS device with Expo Go ## Set up an iOS device with Expo Go Scan the QR code to download the app from the App Store, or visit the Expo Go page on the [App Store](https://itunes.apple.com/app/apple-store/id982107779).
# Create a development build for iOS Simulator with EAS ## Set up an iOS Simulator with a development build ## Set up Xcode ## Create a development build Step 1: ### Install EAS CLI To build your app, you will need to install EAS CLI. You can do this by running the following command in your terminal: ```sh $ npm install -g eas-cli ``` Step 2: ### Create an Expo account and login Next, you will need to create an Expo account and login to the EAS CLI. 1. [Sign up](https://expo.dev/signup) for an Expo account. 2. Run the following command in your terminal to log in to the EAS CLI: ```sh $ eas login ``` Step 3: ### Configure your project Run the following command to create an EAS config in your project: ```sh $ eas build:configure ``` Step 4: ### Adjust your build profile To create a simulator-compatible development build, you'll need to update your build profile in **eas.json** to set the `ios.simulator` property to `true`: ```json eas.json { "build": { "development": { "developmentClient": true, "distribution": "internal", "ios": { "simulator": true } } } } ``` Step 6: ### Create a development build Run the following command to create a development build: ```sh $ eas build --platform ios --profile development ``` Step 7: ### Install the development build on your simulator After the build is complete, the CLI will prompt you to automatically download and install it on the iOS Simulator. When prompted, press Y to directly install it on the simulator. If you miss this prompt, you can download the build from the link provided in the terminal and drag and drop it onto the iOS Simulator to install it. # Create a development build for iOS Simulator locally ## Set up an iOS Simulator with a development build ## Set up Xcode and Watchman ## Running your app on an iOS Simulator Step 1: ### Install expo-dev-client Run the following command in your project's root directory: ```sh $ npx expo install expo-dev-client ``` Step 2: Run the following from your terminal: ```sh $ npx expo run:ios ``` > This command runs a development server after building your app. You can skip running `npx expo start` on the next page. # Run on iOS Simulator with Expo Go ## Set up an iOS Simulator with Expo Go ## Set up Xcode ## Install Expo Go When you start a development server with `npx expo start` on the [start developing](/get-started/start-developing) page, press i to open the iOS Simulator. Expo CLI will install Expo Go automatically. ## Next step You have a project and a development environment. Now it's time to start developing. ## Start developing Make your first change to an Expo project and see it live on your device. Step 1: ## Start a development server To start the development server, run the following command: ```sh $ npx expo start ``` Step 2: ## Open the app on your device After running the command above, you will see a QR code in your terminal. Scan this QR code to open the app on your device. If you're using an Android Emulator or iOS Simulator, you can press a or i respectively to open the app. Note: Having problems? --- Make sure you are on the same Wi-Fi network on your computer and your device. If it still doesn't work, it may be due to the router configuration — this is common for public networks. You can work around this by choosing the **Tunnel** connection type when starting the development server, then scanning the QR code again. ```sh $ npx expo start --tunnel ``` > Using the **Tunnel** connection type will make the app reloads considerably slower than on **LAN** or **Local**, so it's best to avoid tunnel when possible. You may want to install and use an emulator or simulator to speed up development if **Tunnel** is required to access your machine from another device on your network. --- Step 3: ## Make your first change Open the **app/(tabs)/index.tsx** file in your code editor and make a change. ```diff diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index 45cfa0e..4d1b384 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -17,7 +17,7 @@ export default function HomeScreen() { } > - Welcome! + Hello World! ``` Note: Changes not showing up on your device? --- Expo Go is configured by default to automatically reload the app whenever a file is changed, but let's make sure to go over the steps to enable it in case somehow things aren't working. - Make sure you have the [development mode enabled in Expo CLI](/workflow/development-mode#development-mode). - Close the Expo app and reopen it. - Once the app is open again, shake your device to reveal the developer menu. If you are using an emulator, press Ctrl + M for Android or Cmd ⌘ + D for iOS. - If you see **Enable Fast Refresh**, press it. If you see **Disable Fast Refresh**, dismiss the developer menu. Now try making another change. --- --- ## File structure Below, you can get familiar with the default project's file structure: ## Features The default project template has the following features: ## Next steps Develop, review, and submit your project. Here are next steps to continue building your app: ### Reset your project You can remove the boilerplate code and start fresh with a new project. Run the following command to reset your project: ```sh $ npm run reset-project ``` This command will move the existing files in **app** to **app-example**, then create a new **app** directory with a new **index.tsx** file. ### Develop, review, and deploy Learn how to develop by reading the docs in the Develop section. You'll learn how to create [UI elements](/develop/user-interface/splash-screen-and-app-icon/), add [unit tests](/develop/unit-testing/), include [native modules](/config-plugins/introduction/), and more. Once you've developed your app, you can share it with your teammates for [review](/review/overview). Finally, you can [build](/deploy/build-project/) and [submit](/deploy/submit-to-app-stores/) your project to the app stores. ### Step-by-step guide For a guided, step-by-step walkthrough of building an app with Expo from start to finish, check out the [tutorial](/tutorial/introduction/). # Develop ## Tools for development An overview of Expo tools and websites that will help you during various aspects of your project-building journey. When you create a new project with Expo, learning about the following essential tools and websites can help you during your app development journey. This page provides an overview of a list of recommended tools. ## Expo CLI Expo CLI is a development tool and is installed automatically with `expo` package when you create a new project. You can use it by leveraging `npx` (a Node.js package runner). It is designed to help you move faster during the app development phase. For example, your first interaction with Expo CLI is starting the development server by running the command: `npx expo start`. The following is a list of common commands that you will use with Expo CLI while developing your app: | Command | Description | | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `npx expo start` | Starts the development server (whether you are using a development build or Expo Go). | | `npx expo prebuild` | Generates native Android and iOS directories using [Prebuild](/workflow/prebuild/). | | `npx expo run:android` | Compiles native Android app locally. | | `npx expo run:ios` | Compiles native iOS app locally. | | `npx expo install package-name` | Used to install a new library or validate and update specific libraries in your project by adding `--fix` option to this command. | | `npx expo lint` | [Setup and configures](/guides/using-eslint/) ESLint. If ESLint is already configured, this command will [lint your project files](/guides/using-eslint/#usage). | In a nutshell, Expo CLI allows you to develop, compile, start your app, and more. See [Expo CLI reference](/more/expo-cli/) for more available options and actions you can perform with the CLI. ## EAS CLI EAS CLI is used to log in to your Expo account and compile your app using different EAS services such as Build, Update, or Submit. You can also use this tool to: - Publish your app to the app stores - Create a development, preview, or production build of your app - Create over-the-air (OTA) updates - Manage your app credentials - Create an ad hoc provisioning profile for an iOS device To use EAS CLI, you need to install it globally on your local machine by running the command: ```sh $ npm install -g eas-cli ``` You can use `eas --help` in your terminal window to learn more about the available commands. For a complete reference, see [`eas-cli` npm page](https://www.npmjs.com/package/eas-cli). ## Expo Doctor Expo Doctor is a command line tool used to diagnose issues in your Expo project. To use it, run the following command in your project's root directory: ```sh $ npx expo-doctor ``` This command performs checks and analyzes your project's codebase for common issues in [app config](/workflow/configuration/) and **package.json** files, dependency compatibility, configuration files, and the overall health of the project. Once the check is complete, Expo Doctor outputs the results. If Expo Doctor finds an issue, it provides a description of the problem along with advice on how to fix it or where to find help. By default, Expo Doctor validates your project's packages against the [React Native directory](https://reactnative.directory/) and checks if app config properties are properly synced when native directories exist. You can configure these checks in your project's **package.json** file. See [`reactNativeDirectoryCheck`](/versions/latest/config/package-json/#reactnativedirectorycheck) and [`appConfigFieldsNotSyncedCheck`](/versions/latest/config/package-json/#appconfigfieldsnotsynced) for more details. You can also use `npx expo-doctor --help` to display usage information. ## Orbit Orbit is a macOS and Windows app that enables: - Install and launch builds from EAS on physical devices and emulators. - Install and launch updates from EAS on Android Emulators or iOS Simulators. - Launch snack projects on Android Emulators or iOS Simulators. - Use local files to install and launch apps. Orbit supports any Android **.apk**, iOS Simulator compatible **.app**, or ad hoc signed apps. - See a list of pinned projects from your EAS dashboard. ### Installation For macOS: You can download Orbit with Homebrew for macOS, or directly from the [GitHub releases](https://github.com/expo/orbit/releases). ```sh $ brew install expo-orbit ``` If you want Orbit to start when you log in automatically, click on the Orbit icon in the menu bar, then **Settings** and select the **Launch on Login** option. For Windows: > **Note**: Orbit for Windows is in preview and is only compatible with x64 and x86 machines. Compatibility for other architectures will be added in the future. You can download Orbit for Windows directly from the [GitHub releases](https://github.com/expo/orbit/releases). > **info** Orbit relies on the Android SDK on both macOS and Windows and `xcrun` for device management only on macOS, which requires setting up both [Android Studio](/workflow/android-studio-emulator/) and [Xcode](/workflow/ios-simulator/). {/* ### Usage */} ## Expo Tools for VS Code Expo Tools is a VS Code extension to improve your development experience when working with app config files. It provides features such as autocomplete and intellisense for files such as app config, EAS config, store config and Expo Module config files. You can also use it to debug your app using VS Code's built-in debugger to set breakpoints, inspect variables, execute code through the debug console, and more. See [Debugging with VS Code](/debugging/tools/#debugging-with-vs-code) for how to use this extension for debugging. ## Test prototypes with Snack and Expo Go ### Snack Snack is an in-browser development environment that works similarly to Expo Go. It's a great way to share code snippets and experiment with React Native without downloading any tools on your computer. To use it, go to [snack.expo.dev](https://snack.expo.dev/), edit the `` component in **App.js**, choose a platform (Android, iOS, or web) in the right panel and see the changes live. ### Expo Go [Expo Go](https://expo.dev/go) is a free open-source, sandbox for learning and experimenting with React Native. It works with Android and iOS. For more information on how to use it: - Click [this link](/get-started/set-up-your-environment/?mode=expo-go) to go to Set up your environment guide - Select a platform to develop under **Where would you like to develop?** - Select Expo Go under **How would you like to develop?** - Follow the instructions described in that guide > **Note:** Not recommended for building and distributing production apps to the app stores. Instead, use [development builds](/get-started/set-up-your-environment/?mode=development-build). Note: What if I open a project with an unsupported SDK version? --- When running a project that was created for an unsupported SDK version in Expo Go, you'll see the following error: ```sh "Project is incompatible with this version of Expo Go" ``` To fix this, upgrading your project to a [supported SDK version](/versions/latest/#each-expo-sdk-version-depends-on-a-react-native-version) is recommended. If you want to learn how to do it, see [Upgrade the project to a new SDK Version](#how-do-i-upgrade-my-project-from). --- Note: How do I upgrade my project from an unsupported SDK version? --- See [Upgrading Expo SDK guide](/workflow/upgrading-expo-sdk-walkthrough) for instructions for upgrading to a specific SDK version. --- ## React Native directory Any library that is compatible with React Native works in an Expo project when you use a development build to create your project. [reactnative.directory](https://reactnative.directory/) is a searchable database for React Native libraries. If a library you are looking for is not included in Expo SDK, use the directory to find a compatible library for your project. ## Authentication Learn about setting up authentication in your Expo project. Expo can be used to login to many popular providers on Android, iOS, and web. [`expo-auth-session`](/versions/latest/sdk/auth-session/) package allows [browser-based authentication](/versions/latest/sdk/auth-session/#how-web-browser-based-authentication-flows-work) (using OAuth or OpenID Connect) to your project for Android, iOS, and the web. You can also implement authentication using native libraries for third-party providers with [development builds](/develop/development-builds/create-a-build). ## Unit testing with Jest Learn how to set up and configure the jest-expo library to write unit and snapshot tests for a project with Jest. [Jest](https://jestjs.io) is the most widely used unit and snapshot JavaScript testing framework. In this guide, you will learn how to set up Jest in your project, write a unit test, write a snapshot test, and best practices for structuring your tests when using Jest with React Native. You will also use the [`jest-expo`](https://github.com/expo/expo/tree/main/packages/jest-expo) library, which is a Jest preset that mocks the native part of the Expo SDK and handles most of the configuration required for your Expo project. ## Installation and configuration If you have created your project using the [default Expo template](/get-started/create-a-project/), you can skip this section. The `jest-expo` and other required dev dependencies are already installed and configured. Note: Manual installation instructions for --- If you have created your project using [different template](/more/create-expo/#--template), follow the instructions below to install and configure `jest-expo` in your project. Step 1: Install `jest-expo` and other required dev dependencies in your project. Run the following command from your project's root directory: For macOS/Linux: ```sh $ npx expo install jest-expo jest @types/jest -- --save-dev $ npx expo install jest-expo jest @types/jest -- --dev ``` For Windows: ```sh $ npx expo install jest-expo jest @types/jest "--" --save-dev $ npx expo install jest-expo jest @types/jest "--" --dev ``` > **Note:** If your project is not using TypeScript, you can skip installing `@types/jest`. Step 2: Open **package.json**, add a script for running tests, and add the preset for using the base configuration from `jest-expo`: ```json package.json { "scripts": { }, "jest": { "preset": "jest-expo" } } ``` --- Note: Additional configuration for using --- You can transpile node modules your project uses by configuring [`transformIgnorePatterns`](https://jestjs.io/docs/configuration#transformignorepatterns-arraystring) in your **package.json**. This property takes a regex pattern as its value: For npm/Yarn: ```json package.json "jest": { "preset": "jest-expo", "transformIgnorePatterns": [ "node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@sentry/react-native|native-base|react-native-svg)" ] } ``` For pnpm: ```json package.json "jest": { "preset": "jest-expo", "transformIgnorePatterns": [ "node_modules/(?!(?:.pnpm/)?((jest-)?react-native|@react-native(-community)?|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@sentry/react-native|native-base|react-native-svg))" ] } ``` Jest has many configuration options, but the above configuration should cover most of your needs. However, you can always add to this pattern list. For more details, see [Configuring Jest](https://jestjs.io/docs/configuration). --- ## Install React Native Testing Library The [React Native Testing Library (`@testing-library/react-native`)](https://callstack.github.io/react-native-testing-library/) is a lightweight solution for testing React Native components. It provides utility functions and works with Jest. To install it, run the following command: For macOS/Linux: ```sh $ npx expo install @testing-library/react-native -- --save-dev $ npx expo install @testing-library/react-native -- --dev ``` For Windows: ```sh $ npx expo install @testing-library/react-native "--" --save-dev $ npx expo install @testing-library/react-native "--" --dev ``` > **warning** **Deprecated:** If you are using the default Expo template, after installing this library, you can uninstall the `react-test-renderer` and `@types/react-test-renderer` from your project's dev dependencies. The `react-test-renderer` has been deprecated and will no longer be maintained in the future. See [React's documentation for more information](https://react.dev/warnings/react-test-renderer). ## Unit test A unit test checks the smallest unit of code, usually a function. To write your first unit test, take a look at the following example: Step 1: Inside the **app** directory of your project, create a new file called **index.tsx**, and the following code to render a simple component: ```tsx index.tsx import { PropsWithChildren } from 'react'; import { StyleSheet, Text, View } from 'react-native'; export const CustomText = ({ children }: PropsWithChildren) => {children}; export default function HomeScreen() { return ( Welcome! ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', }, }); ``` Step 2: Create a **\_\_tests\_\_** directory at the root of your project's directory. If this directory already exists in your project, use that. Then, create a new file called **HomeScreen-test.tsx**. The `jest-expo` preset customizes the Jest configuration to also identify files with **-test.ts|tsx** extensions as tests. Add the following example code in **HomeScreen-test.tsx**: ```tsx HomeScreen-test.tsx import { render } from '@testing-library/react-native'; import HomeScreen, { CustomText } from '@/app/index'; describe('', () => { test('Text renders correctly on HomeScreen', () => { const { getByText } = render(); getByText('Welcome!'); }); }); ``` In the above example, the `getByText` query helps your tests find relevant element in your app's user interface and make assertion whether or not the certain element exists. The React Native Testing Library provides this query, and each [query variant](https://callstack.github.io/react-native-testing-library/docs/api/queries#query-variant) differs in its return type. For more examples and detailed API information, see the React Native Testing Library's [Queries API reference](https://callstack.github.io/react-native-testing-library/docs/api/queries). Step 3: Run the following command in a terminal window to execute the test: ```sh $ npm run test ``` You will see one test being passed. ## Structure your tests Organizing your test files is important to make them easier to maintain. A common pattern is creating a **\_\_tests\_\_** directory and putting all your tests inside. An example structure of tests next to the **components** directory is shown below: Alternatively, you can have multiple **\_\_tests\_\_** sub-directories for different areas of your project. For example, create a separate test directory for **components**, and so on: It's all about preferences, and it is up to you to decide how you want to organize your project directory. ## Snapshot test A [snapshot test](https://jestjs.io/docs/en/snapshot-testing) is used to make sure that UI stays consistent, especially when a project is working with global styles that are potentially shared across components. To add a snapshot test for ``, add the following code snippet in the `describe()` in **HomeScreen-test.tsx**: ```tsx HomeScreen-test.tsx describe('', () => { test('CustomText renders correctly', () => { const tree = render(Some text).toJSON(); expect(tree).toMatchSnapshot(); }); }); ``` Run `npm run test` command, and you will see a snapshot created inside **\_\_tests\_\_\\\_\_snapshots\_\_** directory, and two tests passed. ## Code coverage reports Code coverage reports can help you understand how much of your code is tested. To see the code coverage report in your project using the HTML format, in **package.json**, under `jest`, set the `collectCoverage` to true and use `collectCoverageFrom` to specify a list of files to ignore when collecting the coverage. ```json package.json "jest": { ... "collectCoverage": true, "collectCoverageFrom": [ "**/*.{ts,tsx,js,jsx}", "!**/coverage/**", "!**/node_modules/**", "!**/babel.config.js", "!**/expo-env.d.ts", "!**/.expo/**" ] } ``` Run `npm run test`. You will see a **coverage** directory created in your project. Find the **lcov-report/index.html** and open it in a browser to see the coverage report. > Usually, we don't recommend uploading **index.html** file to git. Add `coverage/**/*` in the **.gitignore** file to prevent it from being tracked. ## Jest flows (optional) You can also use different flows to run your tests. Below are a few example scripts that you can try: ```json package.json "scripts": { "test": "jest --watch --coverage=false --changedSince=origin/main", "testDebug": "jest -o --watch --coverage=false", "testFinal": "jest", "updateSnapshots": "jest -u --coverage=false" } ``` For more information, see [CLI Options](https://jestjs.io/docs/en/cli) in Jest documentation. ## Additional information # Navigation ## File-based routing Learn about Expo Router which is a file-based routing system and how to use it in your project. This guide provides basic conventions and guidance for Expo Router and navigation patterns (stack and tabs). To follow along, you can [create a project by using the default template](/get-started/create-a-project/) or install [Expo Router library manually](/router/installation/#manual-installation) in your existing project. ## What is Expo Router? Expo Router is a routing framework for React Native and web applications. It allows you to manage navigation between screens in your app and use the same components on multiple platforms (Android, iOS and web). It uses a file-based method to determine routes inside your app. It also provides native navigation and is built on top of [React Navigation](https://reactnavigation.org/). ## app directory The **app** is a special directory. Any file you add to this directory becomes a route inside the native app and reflects the same URL for that route on the web. ## Create a route In the **app** directory, a route is created by adding a file or a nested directory that includes **index.tsx** file. For example, to create an initial route of your app, you can add **index.tsx** to the **app** directory with the following code: ```tsx app/index.tsx|collapseHeight=280 import { View, Text, StyleSheet } from 'react-native'; export default function HomeScreen() { return ( Home ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, }); ``` The **app/index.tsx** file will match the `/` route and after creating this file the **app** directory structure is: ### File name conventions Files named **index** match the parent directory and do not add a path segment. For example, if you expand the app's file structure by adding **app/settings/index.tsx**, it will match the `/settings` route. > **Note:** A route file is defined by exporting a React component as the default value. The file must use either `.js`, `.jsx`, `.ts`, or `.tsx` extension. ## \_layout file Layout files in a directory are used to define shared UI elements such as headers, tab bars so that they persist between different routes. Any time you create a new project, by default the **app** directory will contain a **root layout** file (**app/\_layout**). ### Root layout Traditionally, React Native projects are structured with a single root component (defined as **App.js** or **index.js**). Similarly, the first layout file (**\_layout.tsx**) inside the **app** directory is considered to be the single root component. Between multiple routes, a Root layout file in Expo Router is used to share UI between multiple routes such as injecting global providers, themes, styles, delay splash screen rendering until assets and fonts are loaded, or defining your app's root navigation structure. For example, the following code exports a default React component called `RootLayout`: ```tsx app/_layout.tsx export default function RootLayout() { return ( ) } ``` > **info** With Expo Router, any React providers defined inside **app/\_layout.tsx** are accessible by any route in your app. To improve performance and cause fewer renders, try to reduce the scope of your providers to only the routes that need them. ## Stack navigator A stack navigator is a pattern to navigate between different routes in an app. It allows transitioning between screens and managing the navigation history. It is conceptually similar to how a web browser handles the navigation state. For example, if you want to add a new route `/details`, create **details.tsx** file. This will allow the app user to navigate from the `/` route to `/details`: ```tsx app/details.tsx|collapseHeight=300 import { View, Text, StyleSheet } from 'react-native'; export default function DetailsScreen() { return ( Details ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, }); ``` After creating this route file, the current file structure looks like: To allow navigation between two routes (`/` and `/details`), update the Root layout file and add a `Stack` component to it: ```tsx app/_layout.tsx|collapseHeight=440 import { Stack } from 'expo-router'; export default function RootLayout() { return ( ); } ``` `` component in the layout file allows defining routes in a stack. > **Note:** The `screenOptions` in the above example allows configuring options for all the routes inside a stack. See [Statically configure route options](/router/advanced/stack/#statically-configure-route-options) for more information. ## Navigating between routes Expo Router uses a built-in component called `Link` to move between routes in an app. This is conceptually similar to how web works with the `` tag and the `href` attribute. You can use it by importing it from Expo Router library and then passing the `href` prop with the route to navigate as the value of the prop. For example, to navigate from `/` to `/details`, add a `Link` component in the **index.tsx** file: ```tsx app/index.tsx|collapseHeight=300 import { Link } from 'expo-router'; import { View, Text, StyleSheet } from 'react-native'; export default function HomeScreen() { return ( Home View details ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, }); ``` ### How does `Link` work? `Link` wraps the children in a `` by default. You can customize to use a different button component. Use the `Link` component to wrap the custom button component and the `asChild` prop which forwards all props to the first child of the `Link` component. For more information on the `Link` component's props, see [Navigate between pages](/router/navigating-pages/). ## Groups A group is created to organize similar routes or a section of the app. Each group has a layout file, and the grouped directory requires a name inside parentheses `(group)`. For example, you have the `/` and `/details` routes which can be grouped inside **app/(home)** directory. This updates the file structure to: You also need to add **(home)/\_layout.tsx** which is used to define the `Stack` navigator for `/` and `/details` routes. ```tsx app/(home)/_layout.tsx|collapseHeight=440 import { Stack } from 'expo-router'; export default function HomeLayout() { return ( ); } ``` The Root layout file also changes and now includes the **(home)** group which further uses **(home)/index** as the initial route of the app. ```tsx app/_layout.tsx import { Stack } from 'expo-router'; export default function RootLayout() { return ( ); } ``` > **Note:** In the above example, the screen options are moved to **(home)/\_layout.tsx** file. This means if you add any route to the Stack navigator inside the Root layout, it will not use the same screen options as the routes inside the Home layout. ## Tab navigator A tab navigator is a common pattern to navigate between different sections of an app using a tab bar. Expo Router provides a `Tabs` navigation component. For example, in the current file structure, you have two different sections: Home (`/` and `/details` routes) and Settings (`/settings` route). Adding a special directory **(tabs)**, you can move the existing Home route files inside it and create a **settings.tsx**. Any file or directory inside **(tabs)** becomes a route in the tab navigator. To switch between different routes using the tab bar, you need to create a layout file inside this directory **(tabs)/\_layout** and export a `TabLayout` component: ```tsx app/(tabs)/_layout.tsx import { Tabs } from 'expo-router'; export default function TabLayout() { return ( ); } ``` > **Note:** In `TabLayout`, the existing Stack navigator for `(home)` is now nested. To make this work, update the **app/\_layout.tsx** file by adding **(tabs)** as the first route. ```tsx app/_layout.tsx import { Stack } from 'expo-router'; export default function RootLayout() { return ( ); } ``` ## Not found routes Expo Router provides a special file **+not-found.tsx** which is used to handle routes that are 404s. This route file matches all unmatched routes from a nested level. Create this file in the **app** directory: ```tsx +not-found.tsx|collapseHeight=320 import { Link, Stack } from 'expo-router'; import { View, StyleSheet } from 'react-native'; export default function NotFoundScreen() { return ( <> Go to home screen ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, }); ``` ## Dynamic routes Learn about dynamic routes and how you can create them using Expo Router library. A **dynamic route** allows matching one or multiple paths based on a dynamic segment embedded in the URL. This segment is in the form of a variable, such as a unique identifier, and your app doesn't know the exact segment ahead of time. This guide explains how to handle dynamic routes with Expo Router. > This guide continues to build on top of the example and the **app** directory structure used in the previous [File-based routing](/develop/file-based-routing/). ## Dynamic route convention A dynamic segment of a route is created by wrapping a file's name in square brackets. For example, **[id].tsx**. > **What is a dynamic segment?** Any segment of a path in a URL that is dynamic. For example, in an app screen where it displays a users list, you might have a path such as `/details/[id]` where the `[id]` is the dynamic segment and displays details based on the `id` of the user. ## Create a dynamic route Let's consider the following **app** directory structure: In the above file structure, the `[id]` is used to display information for the route **details/[id].tsx**. The same route will display unique information based on the value of the `id`: | Route | Matched URL | | -------------------- | ------------ | | **details/[id].tsx** | `/details/1` | | **details/[id].tsx** | `/details/2` | This dynamic segment convention makes sure that when an app user navigates from the home screen to the details screen, they view the correct information for the dynamic segment of the route. ## Use `Link` to navigate to a dynamic route Navigating from one route to a dynamic route is done by providing query parameters to the `Link` component either statically or using the `href` object. For example, the following code allows you to navigate to the dynamic route statically using query parameters: ```tsx app/(home)/index.tsx|collapseHeight=300 import { Link } from 'expo-router'; import { View, Text, StyleSheet } from 'react-native'; export default function HomeScreen() { return ( Home View first user details View second user details ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, }); ``` You can also use the `href` object to provide a `pathname` which takes the value of the dynamic route and passes `params`: ```tsx app/(home)/index.tsx import { Link } from 'expo-router'; import { View, Text, StyleSheet } from 'react-native'; export default function HomeScreen() { return ( Home View user details ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, }); ``` ## Access parameters from dynamic segments Dynamic segments of a URL are accessible with a [route parameter](/router/reference/url-parameters/) in the route component. For example, you can use the [`useLocalSearchParams`](/router/reference/hooks/#uselocalsearchparams) hook which returns the URL parameters for the selected route. ```tsx app/(home)/details/[id].tsx|collapseHeight=300 import { useLocalSearchParams } from 'expo-router'; import { View, Text, StyleSheet } from 'react-native'; export default function DetailsScreen() { const { id } = useLocalSearchParams(); return ( Details of user {id} ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, }); ``` When `/` pushes `/details/1`, the `useLocalSearchParams` returns `{ id: '1' }` because `/details/1` is the selected route. ## Next steps A list of guides and references about Expo Router for further reading. There's much to learn about Expo Router if you are diving into the file-based routing framework for the first time. The following guides and references will help you dive deep: ## Navigation patterns ## References # User interface ## Splash screen and app icon Learn how to add a splash screen and app icon to your Expo project. A splash screen and an app icon are fundamental elements of a mobile app. They play an important role in the user experience and branding of the app. This guide provides steps on how to create and add them to your app. Video Tutorial: [Create an App Icon and Splash Screen](https://www.youtube.com/watch?v=3Bsw8a1BJoQ) --- ## Splash screen A splash screen, also known as a launch screen, is the first screen a user sees when they open your app. It stays visible while the app is loading. You can also control the behavior of when a splash screen disappears by using the native [SplashScreen API](/versions/latest/sdk/splash-screen). The [`expo-splash-screen`](/versions/latest/sdk/splash-screen) has a built-in [config plugin](/config-plugins/introduction) that lets you configure properties such as the splash icon and background color. > **Warning** Do not use Expo Go or a development build to test your splash screen. **Expo Go** renders your app icon while the splash screen is visible, which can interfere with testing. **Development builds** include `expo-dev-client`, which has its own splash screen and may cause conflicts. Instead, use a [preview build](/build/eas-json/#preview-builds) or a [production build](/build/eas-json/#production-builds). Step 1: ### Create a splash screen icon To create a splash screen icon, you can use this [Figma template](https://www.figma.com/community/file/1466490409418563617). It provides a bare minimum design for an icon and splash images for Android and iOS. **Recommended:** - Use a 1024x1024 image. - Use a **.png** file. - Use a transparent background. Step 2: ### Export the splash icon as a .png After creating a splash screen icon, export it as a **.png** and save it in the **assets/images** directory. By default, Expo uses **splash-icon.png** as the file name. If you decide to change the name of your splash screen file, make sure to use that in the next step. > **Note:** **Currently, only .png images are supported** to use as a splash screen icon in an Expo project. If you use another image format, making a production build of your app will fail. Step 3: ### Configure the splash screen icon Open the app config file, and under plugins, set the following properties: ```json app.json { "expo": { "plugins": [ [ "expo-splash-screen", { "backgroundColor": "#232323", "image": "./assets/images/splash-icon.png", "dark": { "image": "./assets/images/splash-icon-dark.png", "backgroundColor": "#000000" }, "imageWidth": 200 } ] ] } } ``` To test your new splash screen, build your app for [internal distribution](/tutorial/eas/internal-distribution-builds) or for production, see guides on [Android](/tutorial/eas/android-production-build/) and [iOS](/tutorial/eas/ios-production-build/). Note: Configuring properties separately for Android and iOS --- [`expo-splash-screen`](/versions/latest/sdk/splash-screen) also supports `android` and `ios` properties for configuring the splash screen for a specific platform. See the following example: ```json app.json { "expo": { "plugins": [ [ "expo-splash-screen", { "ios": { "backgroundColor": "#ffffff", "image": "./assets/images/splash-icon.png", "resizeMode": "cover", }, "android": { "backgroundColor": "#0c7cff", "image": "./assets/images/splash-android-icon.png", "imageWidth": 150, } } } ] ] } } ``` --- Note: Not using prebuild? --- If your app does not use [Expo Prebuild](/workflow/prebuild) (formerly the _managed workflow_) to generate the native **android** and **iOS** directories, then changes in the app config will have no effect. For more information, see [how you can customize the configuration manually](https://github.com/expo/expo/tree/main/packages/expo-splash-screen#-installation-in-bare-react-native-projects). --- ## App icon An app's icon is what your app users see on their device's home screen and app stores. Android and iOS have different and strict requirements. Step 1: ### Create an app icon To create an app icon, you can use this [Figma template](https://www.figma.com/community/file/1466490409418563617). It provides a bare minimum design for an icon and splash images for Android and iOS. Step 2: ### Export the icon image as a .png After creating an app icon, export it as **.png** and save it in the **assets/images** directory. By default, Expo uses **icon.png** as the file name. If you decide to use a different file name, make sure to use that in the next step. Step 3: ### Add the icon in app config Open the app config and add the local path as the value of [`icon`](/versions/latest/config/app/#icon) property to point it to your new app icon: ```json app.json { "icon": "./assets/images/icon.png" } ``` Note: Custom configuration tips for Android and iOS --- #### Android Further customization of the Android icon is possible using the [`android.adaptiveIcon`](/versions/latest/config/app/#adaptiveicon) property, which will override both of the previously mentioned settings. The Android Adaptive Icon is formed from two separate layers — a foreground image and a background color or image. This allows the OS to mask the icon into different shapes and also supports visual effects. For Android 13 and later, the OS supports a themed app icon that uses a wallpaper and theme to determine the color set by the device's theme. The design you provide should follow the [Android Adaptive Icon Guidelines](https://developer.android.com/develop/ui/views/launch/icon_design_adaptive) for launcher icons. You should also: - Use **.png** files. - Use the `android.adaptiveIcon.foregroundImage` property to specify the path to your foreground image. - Use the `android.adaptiveIcon.monochromeImage` property to specify the path to your monochrome image. - The default background color is white; to specify a different background color, use the `android.adaptiveIcon.backgroundColor` property. You can instead specify a background image using the `android.adaptiveIcon.backgroundImage` property. Make sure that it has the same dimensions as your foreground image. You may also want to provide a separate icon for older Android devices that do not support Adaptive Icons. You can do so with the `android.icon` property. This single icon would be a combination of your foreground and background layers. > See [Apple best practices](https://developer.apple.com/design/human-interface-guidelines/app-icons/#Best-practices) to ensure your icon looks professional, such as testing your icon on different wallpapers and avoiding text beside your product's wordmark. Provide an icon that's at least 512x512 pixels. #### iOS For iOS, your app's icon should follow the [Apple Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/app-icons/). You should also: - Use a **.png** file. - 1024x1024 is a good size. If you have an Expo project created using `npx create-expo-app`, [EAS Build](/build/setup/) will generate the other sizes for you. In case of a bare React Native project, generate the icons on your own. The largest size EAS Build generates is 1024x1024. - The icon must be exactly square. For example, a 1023x1024 icon is not valid. - Make sure the icon fills the whole square, with no rounded corners or other transparent pixels. The operating system will mask your icon when appropriate. - Use `ios.icon` to specify different icons for various system appearances (for example, dark and tinted) can be provided. If specified, this overrides the top-level icon key in the app config file. See the example below: ```json app.json { "expo": { "ios": { "icon": { "dark": "./assets/images/ios-dark.png", "light": "./assets/images/ios-light.png", "tinted": "./assets/images/ios-tinted.png" } } } } ``` --- ## Safe areas Learn how to add safe areas for screen components inside your Expo project. Creating a safe area ensures your app screen's content is positioned correctly. This means it doesn't get overlapped by notches, status bars, home indicators, and other interface elements that are part of the device's physical hardware or are controlled by the operating system. When the content gets overlapped, it gets concealed by these interface elements. Here's an example of an app screen's content getting concealed by the status bar on Android. On iOS, the same content is concealed by rounded corners, notch, and the status bar. ## Use `react-native-safe-area-context` library [`react-native-safe-area-context`](https://github.com/th3rdwave/react-native-safe-area-context) provides a flexible API for handling Android and iOS device's safe area insets. It also provides a `SafeAreaView` component that you can use instead of a [``](https://reactnative.dev/docs/view) to account for safe areas automatically in your screen components. Using the library, the result of the previous example changes as it displays the content inside a safe area, as shown below: ### Installation You can skip installing `react-native-safe-area-context` if you have created a project using [the default template](/get-started/create-a-project/). This library is installed as peer dependency for Expo Router library. Otherwise, install it by running the following command: ```sh $ npx expo install react-native-safe-area-context ``` ### Usage You can directly use [`SafeAreaView`](https://github.com/th3rdwave/react-native-safe-area-context#safeareaview) to wrap the content of your screen's component. It is a regular `` with the safe area insets applied as extra padding or margin. ```tsx app/index.tsx import { Text } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; export default function HomeScreen() { return ( Content is in safe area. ); } ``` Note: Using a different Expo template and don't have Expo Router installed? --- Import and add [`SafeAreaProvider`](https://github.com/th3rdwave/react-native-safe-area-context#safeareaprovider) to the root component file (such as **App.tsx**) before using `SafeAreaView` in your screen component. ```tsx App.tsx import { SafeAreaProvider } from 'react-native-safe-area-context'; export default function App() { return ( return ...; ); } ``` --- ## Alternate: `useSafeAreaInsets` hook Alternate to `SafeAreaView`, you can use [`useSafeAreaInsets`](https://github.com/th3rdwave/react-native-safe-area-context#usesafeareainsets) hook in your screen component. It provides direct access to the safe area insets, allowing you to apply padding for each edge of the `` using an inset from this hook. The example below uses the `useSafeAreaInsets` hook. It applies top padding to a `` using `insets.top`. ```tsx app/index.tsx import { Text, View } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; export default function HomeScreen() { const insets = useSafeAreaInsets(); return ( Content is in safe area. ); } ``` The hook provides the insets in the following object: ```ts { top: number, right: number, bottom: number, left: number } ``` ## Additional information ### Minimal example Below is a minimal working example that uses the `useSafeAreaInsets` hook to apply top padding to a view. #### Using react-native-safe-area-context ```tsx collapseHeight=320 import { Text, View } from 'react-native'; import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context'; function HomeScreen() { const insets = useSafeAreaInsets(); return ( Content is in safe area. ); } export default function App() { return ( ); } ``` ### Usage with React Navigation By default, React Navigation supports safe areas and uses `react-native-safe-area-context` as a peer dependency. For more information, see the [React Navigation documentation](https://reactnavigation.org/docs/handling-safe-area/). ### Usage with web If you are targeting the web, set up `SafeAreaProvider` as described in the [usage section](#usage). If you are doing server-side rendering (SSR), see the [Web SSR section](https://github.com/th3rdwave/react-native-safe-area-context#web-ssr) in the library's documentation. ## Fonts Learn how to integrate custom fonts in your app using local files or Google Font packages Android and iOS come with their own set of platform fonts. To provide a consistent user experience and enhance your app's branding, you can use custom fonts. This guide covers different ways you can add and load a custom font into your project and also provides additional information related to fonts. ## Add a custom font There are two ways you can add a custom font into your project: - Add a font file into your local assets. For example, a font file in the **assets/fonts** directory. - Install a Google Font package. For example, installing [`@expo-google-fonts/inter`](https://www.npmjs.com/package/@expo-google-fonts/inter) package. ### Supported font formats Expo SDK officially supports OTF and TTF font formats across Android, iOS and web platforms. If your font is in another font format, you have to set up advanced configuration to support that format in your project. ### How to choose between OTF and TTF If the font you're using have both OTF and TTF versions, prefer OTF. The **.otf** files are smaller than **.ttf** files. Sometimes, OTF also renders slightly better in certain contexts. ## Use a local font file Copy the file into your project's **assets/fonts** directory. > **info** **assets/fonts** directory path is a common convention in React Native apps to put font files. You can place these files elsewhere if you follow a custom convention. Two ways to use the local font file in your project: - Embed the font file with [`expo-font` config plugin](/versions/latest/sdk/font/#configuration-in-appjsonappconfigjs). - Loading the font file with [`useFonts`](/versions/latest/sdk/font/#usefontsmap) hook at runtime asynchronously. ### With `expo-font` config plugin The `expo-font` config plugin allows embedding one or more font files in your project's native code. This is the recommended method for adding fonts to your app due to its benefits: - Fonts are available immediately when the app starts on a device. - No additional code required to load fonts in a project asynchronously when the app starts. - Fonts are consistently available across all devices where the app is installed because they're bundled within the app. However, this method also has some limitations: - Doesn't work with Expo Go since this method requires [creating a development build](/develop/development-builds/create-a-build/). - Only available for SDK 50 and above. To embed a font in a project, follow the steps below: Step 1: After adding a custom font file in your project, install the `expo-font` library. ```sh $ npx expo install expo-font ``` Step 2: Add the config plugin to your [app config](/versions/latest/config/app/#plugins) file. The configuration must contain the path to the font file using [`fonts`](/versions/latest/sdk/font/#configurable-properties) property which takes an array of one or more font files. The path to each font file is relative to the project's root. For example, in the following configuration, **Inter-Black.otf** font file's path is defined. ```json app.json { "expo": { "plugins": [ [ "expo-font", { "fonts": ["./assets/fonts/Inter-Black.otf"] } ] ] } } ``` Step 3: After embedding the font with the config plugin, create a [new development build](/develop/development-builds/create-a-build/) and install it on your device or Android Emulator or iOS Simulator. You can use the font with `` by specifying the `fontFamily` style prop. See the [next section](#how-to-determine-which-font-family-name-to-use) on how to determine the font family name. In the example below, the `` uses the `Inter-Black` as the font family name: ```tsx Inter Black. ``` - **Android:** Copy font files to **android/app/src/main/assets/fonts**. - **iOS:** See [Adding a Custom Font to Your App](https://developer.apple.com/documentation/uikit/text_display_and_fonts/adding_a_custom_font_to_your_app) in the Apple Developer documentation. #### How to determine which font family name to use On Android, the font family name is the same as of the font file (without the extension). On iOS, the font family name is read from the font file itself. We recommend naming the font file same as its [PostScript name](#what-is-postscript-name-of-a-font) so the font family name is consistent on both platforms. Note: What is PostScript name of a font file? --- The **PostScript name** of a font file is a unique identifier assigned to the font that follows Adobe's PostScript standard. It is used by operating systems and apps to refer to the font. It is not a font's **display name**. For example, Inter Black font file's PostScript name is `Inter-Black`. --- ### With `useFonts` hook The `useFonts` hook from `expo-font` library allows loading the font file asynchronously. This hook keeps track of the loading state and loads the font when an app is initialized. It works with all Expo SDK versions and with Expo Go. To load a font in a project using `useFonts` hook, follow the steps below: Step 1: After adding a custom font file in your project, install the `expo-font` and `expo-splash-screen` libraries. ```sh $ npx expo install expo-font expo-splash-screen ``` The [`expo-splash-screen`](/versions/latest/sdk/splash-screen/) library provides `SplashScreen` component that you can use to prevent rendering the app until the font is loaded and ready. Step 2: Map the font file using the `useFonts` hook in a top level component such as the root layout (**app/layout.tsx**) file in your project: ```tsx app/_layout.tsx import {useEffect} from 'react'; SplashScreen.preventAutoHideAsync(); export default function RootLayout() { const [loaded, error] = useFonts({ 'Inter-Black': require('./assets/fonts/Inter-Black.otf'), }); useEffect(() => { if (loaded || error) { SplashScreen.hideAsync(); } }, [loaded, error]); if (!loaded && !error) { return null; } return ( ) } ``` Step 3: Use the font on the `` by using `fontFamily` style prop in a React component: ```tsx Inter Black ``` ## Use Google Fonts Expo has first-class support for all fonts listed in [Google Fonts](https://fonts.google.com/). They are available using [`@expo-google-fonts`](https://github.com/expo/google-fonts) library. With any of the font package from this library, you can quickly integrate that font and its variants. Two ways to use a Google Font in your project: - Embed the installed font with [`expo-font` config plugin](/versions/latest/sdk/font/#configuration-in-appjsonappconfigjs). - Load the installed font with [`useFonts`](/versions/latest/sdk/font/#usefontsmap) hook at runtime asynchronously. ### With `expo-font` config plugin > **Note:** Embedding a Google Font using `expo-font` config plugin has same benefits and limitations as embedding a custom font on your own. See [using a local font file with `expo-font` config plugin](#with-expo-font-config-plugin) for more information. Step 1: Install the font package. For example, to use Inter Black font, install the [`@expo-google-fonts/inter`](https://www.npmjs.com/package/@expo-google-fonts/inter) package with the command below. ```sh $ npx expo install expo-font @expo-google-fonts/inter ``` Step 2: Add the config plugin to your [app config](/versions/latest/config/app/#plugins) file. The configuration must contain the path to the font file using [`fonts`](/versions/latest/sdk/font/#configurable-properties) property which takes an array of one or more font files. The path to the font file is defined from the font package inside the `node_modules` directory. For example, if you have a font package named `@expo-google-fonts/inter`, then the name of the file is **Inter_900Black.ttf**. ```json app.json { "plugins": [ [ "expo-font", { "fonts": ["node_modules/@expo-google-fonts/inter/Inter_900Black.ttf"] } ] ] } ``` Step 3: After embedding the font with the config plugin, create a [new development build](/develop/development-builds/create-a-build/) and install it on your device or Android Emulator or iOS Simulator. On Android, you can use the font file name. For example, `Inter_900Black`. On iOS, use the font and its weight name ([PostScript name](#what-is-postscript-name-of-a-font)). The example below demonstrates how to use [`Platform`](https://reactnative.dev/docs/platform-specific-code#platform-module) to select the correct font family name for each platform: ```tsx import { Platform } from 'react-native'; // Inside a React component: Inter Black ``` ### With `useFonts` hook > **Note:** Loading a Google Font using `useFonts` hook has same benefits and limitations as embedding a custom font on your own. See [using a local font file with `useFonts` hook](#with-usefonts-hook) for more information. Each google Fonts package provides the `useFonts` hook to load the fonts asynchronously. This hook keeps track of the loading state and loads the font when an app is initialized. The font package also imports the font file so you don't have to explicitly import it. Step 1: Install the Google Fonts package, `expo-font` and `expo-splash-screen` libraries. ```sh $ npx expo install @expo-google-fonts/inter expo-font expo-splash-screen ``` The [`expo-splash-screen`](/versions/latest/sdk/splash-screen/) library provides `SplashScreen` component that you can use to prevent rendering the app until the font is loaded and ready. Step 2: After installing the font package, map the font using the `useFonts` hook in a top level component such as the root layout (**app/layout.tsx**) file in your project: ```tsx app/_layout.tsx // Rest of the import statements import { Inter_900Black, useFonts } from '@expo-google-fonts/inter'; import * as SplashScreen from 'expo-splash-screen'; import {useEffect} from 'react'; SplashScreen.preventAutoHideAsync(); export default function RootLayout() { const [loaded, error] = useFonts({ Inter_900Black, }); useEffect(() => { if (loaded || error) { SplashScreen.hideAsync(); } }, [loaded, error]); if (!loaded && !error) { return null; } return ( ) } ``` Step 3: Use the font on the `` by using `fontFamily` style prop in a React component: ```tsx Inter Black ``` ## Additional information ### Minimal example ### Beyond OTF and TTF If your font is in format other than OTF or TTF, you have to [customize the Metro bundler configuration to include it as an extra asset](/guides/customizing-metro#adding-more-file-extensions-to-assetexts) for it to work. In some cases, rendering a font format that a platform doesn't support may cause your app to crash. For reference, the following table provides the list formats that work on each native platform: | Format | Android | iOS | Web | | ------ | ----------- | ----------- | ----------- | | bdf | | | | | dfont | | | | | eot | | | | | fon | | | | | otf | | | | | ps | | | | | svg | | | | | ttc | | | | | ttf | | | | | woff | | | | | woff2 | | | | ### Platform built-in fonts If you don't want to use a custom font by specifying a `fontFamily`, platform's default font will be used. Each platform has a set of built in fonts. On Android, the default font is Roboto. On iOS, it's SF Pro. A platform's default font is usually easy-to-read. However, don't be surprised when the system default font is changed to use another font that is not easy to read. In this case, use your custom font so you have precise control over what the user will see. ### Handle `@expo/vector-icons` initial load When the icons from `@expo/vector-icons` library load for the first time, they appear as invisible icons in your app. Once they load, they're cached for all the app's subsequent usage. To avoid showing invisible icons on your app's first load, preload during the initial loading screen with [`useFonts`](/versions/latest/sdk/font/#usefontsmap). For example: ```tsx app/_layout.tsx import { useFonts } from 'expo-font'; import Ionicons from '@expo/vector-icons/Ionicons'; export default function RootLayout() { useFonts([require('./assets/fonts/Inter-Black.otf', Ionicons.font)]); return ( ) } ``` Now, you can use any icon from the `Ionicons` library in a React component: ```tsx ``` ### Loading a remote font directly from the web > **warning** **If you're loading remote fonts, make sure they are being served from an origin with CORS properly configured**. If you don't do this, your remote font might not load properly on the web platform. Loading fonts from a local asset is the safest way to load a font in your app. When including fonts as local assets, after you submit your app to the app stores, these fonts are bundled with the app download and will be available immediately. You don't have to worry about CORS or other potential issues. However, loading a font file directly from web is done by replacing the `require('./assets/fonts/FontName.otf')` with the URL of your font as shown in the example below. #### Using a remote font ```tsx import { useFonts } from 'expo-font'; import { Text, View, StyleSheet } from 'react-native'; export default function App() { const [loaded, error] = useFonts({ 'Inter-SemiBoldItalic': 'https://rsms.me/inter/font-files/Inter-SemiBoldItalic.otf?v=3.12', }); if (!loaded || !error) { return null; } return ( Inter SemiBoldItalic Platform Default ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, }); ``` ## Assets Learn about using static assets in your project, including images, videos, sounds, database files, and fonts. A **static asset** is a file that is bundled with your app's binary (native binary). This file type is not part of your app's JavaScript bundle which contain your app's code. Common types of static assets include images, videos, sounds, database files for SQLite, and fonts. These assets can be served locally from your project or remotely over the network. This guide covers different ways you can load and use static assets in your project and also provides additional information on how to optimize and minify assets. ## Serve an asset locally When an asset is stored in your project's file system, it can be embedded in your app binary at build time or loaded at runtime. You can import it like a JavaScript module using `require` or `import` statements. For example, to render an image called **example.png** in **App.js**, you can use `require` to import the image from the project's **assets/images** directory and pass it to the `` component: ```tsx app/index.tsx ``` In the above example, the bundler reads the imported image's metadata and automatically provides the width and height. For more information, see [Static Image Resources](https://reactnative.dev/docs/images#static-image-resources). Libraries such as `expo-image` and `expo-file-system` work similarly to the `` component with local assets. ### How are assets served locally Locally stored assets are served over HTTP in development. They are automatically bundled into your app binary at the build time for production apps and served from disk on a device. ### Load an asset at build time with `expo-asset` config plugin > **Note:** The `expo-asset` config plugin is only available for SDK 51 and above. If you are using an older SDK, you can load a [using the `useAssets` hook](#load-an-asset-at-runtime-with-useassets-hook). To load an asset at build time, you can use the [config plugin](/versions/latest/sdk/asset/#example-appjson-with-config-plugin) from the `expo-asset` library. This plugin will embed the asset file in your native project. Step 1: Install the `expo-asset` library. ```sh $ npx expo install expo-asset ``` Step 2: Add the config plugin to your project's [app config](/versions/latest/config/app/#plugins) file. The configuration must contain the path to the asset file using [`assets`](/versions/latest/sdk/asset/#configurable-properties) property which takes an array of one or more files or directories to link to the native project. The path to each asset file must be relative to your project's root since the app config file is located in the project's root directory. ```json app.json { "expo": { "plugins": [ [ "expo-asset", { "assets": ["./assets/images/example.png"] } ] ] } } ``` Step 3: After embedding the asset with the config plugin, [create a new development build](/develop/development-builds/create-a-build/). Now, you can import and use the asset in your project without using a `require` or an `import` statement. For example, the **example.png** is linked by the above config plugin. You can directly import it into your component and use its resource name. ```tsx app/index.tsx import { Image } from 'expo-image'; export default function HomeScreen() { return ; } ``` The above example is quite concise. However, when a native API expects a specific file and its resource name, this method makes it convenient to integrate with that API and use the resource name directly. > **info** Different file formats are supported with the `expo-asset` config plugin. For more information on these formats, see [Assets API reference](/versions/latest/sdk/asset/#configurable-properties). If you don't see a file format supported by the config plugin, you can use the [`useAssets`](#load-an-asset-at-runtime-with-useassets-hook) hook to load the asset at runtime. ### Load an asset at runtime with `useAssets` hook The `useAssets` hook from `expo-asset` library allows loading assets asynchronously. This hook downloads and stores an asset locally and after the asset is loaded, it returns a list of that asset's instances. Step 1: Install the `expo-asset` library. ```sh $ npx expo install expo-asset ``` Step 2: Import the [`useAssets`](/versions/latest/sdk/asset/#useassetsmoduleids) hook from the `expo-asset` library in your screen component: ```tsx app/index.tsx import { useAssets } from 'expo-asset'; export default function HomeScreen() { const [assets, error] = useAssets([ require('path/to/example-1.jpg'), require('path/to/example-2.png'), ]); return assets ? : null; } ``` ## Serve an asset remotely When an asset is served remotely, it is not bundled into the app binary at build time. You can use the URL of the asset resource in your project if it is hosted remotely. For example, pass the URL to the `` component to render a remote image: ```jsx App.js import { Image } from 'expo-image'; function App() { return ( ); } ``` There is no guarantee about the availability of images served remotely using a web URL because an internet connection may not be available, or the asset might be removed. Additionally, loading assets remotely also requires you to provide an asset's metadata. In the above example, since the bundler cannot retrieve the image's width and height, those values are passed explicitly to the `` component. If you don't, the image will default to 0px by 0px. ## Additional information ### Manual optimization methods #### Images You can compress images using the following: - [`guetzli`](https://github.com/google/guetzli) - [`pngcrush`](https://pmt.sourceforge.io/pngcrush/) - [`optipng`](http://optipng.sourceforge.net/) Some image optimizers are lossless. They re-encode your image to be smaller without any change or loss in the pixels displayed. When you need each pixel to be untouched from the original image, a lossless optimizer and a lossless image format like PNG are a good choice. Other image optimizers are lossy. The optimized image differs from the original image. Often, lossy optimizers are more efficient because they discard visual information that reduces file size while making the image look nearly identical to humans. Tools like `imagemagick` can use comparison algorithms like [SSIM](https://en.wikipedia.org/wiki/Structural_similarity) to show how similar two images look. It's quite common for an optimized image that is over 95% similar to the original image to be far less than 95% of the original file size. #### Other assets For assets like GIFs or videos, or non-code and non-image assets, it's up to you to optimize and minify those assets. > **Note**: GIFs are a very inefficient format. Modern video codecs can produce significantly smaller file sizes with better quality. ### Fonts See [Add a custom font](/develop/user-interface/fonts/#add-a-custom-font) for more information on how to add a custom font to your app. ## Color themes Learn how to support light and dark modes in your app. It's common for apps to support light and dark color schemes. Here is an example of how supporting both modes looks in an Expo project: ## Configuration > **info** For Android and iOS projects, additional configuration is required to support switching between light and dark mode. For web, no additional configuration is required. To configure supported appearance styles, you can use the [`userInterfaceStyle`](/versions/latest/config/app/#userinterfacestyle) property in your project's [app config](/versions/latest/config/app). By default, this property is set to `automatic` when you create a new project with the [default template](/get-started/create-a-project/). Here is an example configuration: ```json app.json { "expo": { "userInterfaceStyle": "automatic" } } ``` You can also configure `userInterfaceStyle` property for a specific platforms by setting either [`android.userInterfaceStyle`](/versions/latest/config/app/#userinterfacestyle-2) or [`ios.userInterfaceStyle`](/versions/latest/config/app/#userinterfacestyle-1) to the preferred value. > **info** The app will default to the `light` style if this property is absent. When you are creating a development build, you have to install [`expo-system-ui`](/versions/latest/sdk/system-ui/#installation) to support the appearance styles for Android. Otherwise, the `userInterfaceStyle` property is ignored. ```sh $ npx expo install expo-system-ui ``` If the project is misconfigured and doesn't have `expo-system-ui` installed, the following warning will be shown in the terminal: ```sh » android: userInterfaceStyle: Install expo-system-ui in your project to enable this feature. ``` You can also use the following command to check if the project is misconfigured: ```sh $ npx expo config --type introspect ``` Note: Using bare React Native app? --- #### Android Ensure that the `uiMode` flag is present on your `MainActivity` (and any other activities where this behavior is desired) in **AndroidManifest.xml**: ```xml ``` Implement the `onConfigurationChanged` method in **MainActivity.java**: ```java import android.content.Intent; import android.content.res.Configuration; public class MainActivity extends ReactActivity { @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); Intent intent = new Intent("onConfigurationChanged"); intent.putExtra("newConfig", newConfig); sendBroadcast(intent); } } ``` #### iOS You can configure supported styles with the [`UIUserInterfaceStyle`](https://developer.apple.com/documentation/bundleresources/information_property_list/uiuserinterfacestyle) key in your app **Info.plist**. Use `Automatic` to support both light and dark modes. --- ### Supported appearance styles The `userInterfaceStyle` property supports the following values: - `automatic`: Follow system appearance settings and notify about any change the user makes. - `light`: Restrict the app to support light theme only. - `dark`: Restrict the app to support dark theme only. ## Detect the color scheme To detect the color scheme in your project, use `Appearance` or `useColorScheme` from `react-native`: ```tsx app/index.tsx import { Appearance, useColorScheme } from 'react-native'; ``` Then, you can use `useColorScheme()` hook as shown below: ```tsx app/index.tsx function MyComponent() { let colorScheme = useColorScheme(); if (colorScheme === 'dark') { // render some dark thing } else { // render some light thing } } ``` In some cases, you will find it helpful to get the current color scheme imperatively with [`Appearance.getColorScheme()` or listen to changes with `Appearance.addChangeListener()`](https://reactnative.dev/docs/appearance). ## Additional information ### Minimal example #### useColorScheme example ```tsx import { StatusBar } from 'expo-status-bar'; export default function App() { const colorScheme = useColorScheme(); const themeTextStyle = colorScheme === 'light' ? styles.lightThemeText : styles.darkThemeText; const themeContainerStyle = colorScheme === 'light' ? styles.lightContainer : styles.darkContainer; return ( Color scheme: {colorScheme} ); } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', }, text: { fontSize: 20, }, lightContainer: { backgroundColor: '#d0d0c0', }, darkContainer: { backgroundColor: '#242c40', }, lightThemeText: { color: '#242c40', }, darkThemeText: { color: '#d0d0c0', }, }); ``` ### Tips While you are developing your project, you can change your simulator's or device's appearance by using the following shortcuts: - If using an Android Emulator, you can run `adb shell "cmd uimode night yes"` to enable dark mode, and `adb shell "cmd uimode night no"` to disable dark mode. - If using a physical Android device or an Android Emulator, you can toggle the system dark mode setting in the device's settings. - If working with an iOS emulator locally, you can use the Cmd ⌘ + Shift + a shortcut to toggle between light and dark modes. ## Animation Learn how to integrate React Native animations and use it in your Expo project. Animations are a great way to enhance and provide a better user experience. In your Expo projects, you can use the [Animated API](https://reactnative.dev/docs/next/animations) from React Native. However, if you want to use more advanced animations with better performance, you can use the [`react-native-reanimated`](https://docs.swmansion.com/react-native-reanimated/) library. It provides an API that simplifies the process of creating smooth, powerful, and maintainable animations. ## Installation You can skip installing `react-native-reanimated` if you have created a project using [the default template](/get-started/create-a-project/). This library is already installed. Otherwise, install it by running the following command: ```sh $ npx expo install react-native-reanimated ``` ## Usage ### Minimal example The following example shows how to use the `react-native-reanimated` library to create a simple animation. For more information on the API and advanced usage, see [`react-native-reanimated` documentation](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/your-first-animation). #### Using react-native-reanimated ```tsx import Animated, { useSharedValue, withTiming, useAnimatedStyle, Easing, } from 'react-native-reanimated'; import { View, Button, StyleSheet } from 'react-native'; export default function AnimatedStyleUpdateExample() { const randomWidth = useSharedValue(10); const config = { duration: 500, easing: Easing.bezier(0.5, 0.01, 0, 1), }; const style = useAnimatedStyle(() => { return { width: withTiming(randomWidth.value, config), }; }); return (