Expo Guide
How to set up Tamagui with Expo
We've created a new template repo for starting an Expo Router based app based on the Expo 3 starter repo.
npm create tamagui@latest --template expo-router
There are also pre-made community Expo starters.
Install
To support dark mode, update your app.json
to app.config.ts
and set
userInterfaceStyle
to "automatic"
.
Expo Router / Web
We have beta support via @tamagui/metro-plugin
. Install:
yarn add tamagui @tamagui/config @tamagui/metro-plugin
If you want web support, adjust your metro.config.js
:
// Learn more https://docs.expo.io/guides/customizing-metroconst { getDefaultConfig } = require('expo/metro-config')/** @type {import('expo/metro-config').MetroConfig} */const config = getDefaultConfig(__dirname, {// [Web-only]: Enables CSS support in Metro.isCSSEnabled: true,})// add nice web support with optimizing compiler + CSS extractionconst { withTamagui } = require('@tamagui/metro-plugin')module.exports = withTamagui(config, {components: ['tamagui'],config: './tamagui.config.ts',outputCSS: './tamagui-web.css',})
Add your tamagui.config.ts
:
import { config } from '@tamagui/config/v3'import { createTamagui } from 'tamagui'export const tamaguiConfig = createTamagui(config)export default tamaguiConfigexport type Conf = typeof tamaguiConfigdeclare module 'tamagui' {interface TamaguiCustomConfig extends Conf {}}
Then update app/_layout.tsx
:
import '../tamagui-web.css'import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native'import { Stack } from 'expo-router'import { useColorScheme } from 'react-native'import { TamaguiProvider } from 'tamagui'import { config } from '../tamagui.config'export default function RootLayout() {const colorScheme = useColorScheme()return (// add this<TamaguiProvider config={config} defaultTheme={colorScheme}><ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}><Stack><Stack.Screen name='(tabs)' options={{ headerShown: false }} /><Stack.Screen name='modal' options={{ presentation: 'modal' }} /></Stack></ThemeProvider></TamaguiProvider>)}
Native
This guide assumes Expo is configured with TypeScript support.
npx create-expo-app -t expo-template-blank-typescript
The following steps are optional but useful for many apps, they enable the
optimizing compiler, reanimated, as well as using process.env.XYZ
for
environment variables.
yarn add @tamagui/babel-plugin
Update your babel.config.js
to include the optional @tamagui/babel-plugin
:
module.exports = function (api) {api.cache(true);return {presets: ["babel-preset-expo"],plugins: [["@tamagui/babel-plugin",{components: ["tamagui"],config: "./tamagui.config.ts",logTimings: true,disableExtraction: process.env.NODE_ENV === 'development'},],// NOTE: this is only necessary if you are using reanimated for animations"react-native-reanimated/plugin",],};}
If you're using a monorepo you probably want to use this Metro configuration:
// Learn more https://docs.expo.io/guides/customizing-metroconst { getDefaultConfig } = require('expo/metro-config');/** @type {import('expo/metro-config').MetroConfig} */const config = getDefaultConfig(__dirname, {// [Web-only]: Enables CSS support in Metro.isCSSEnabled: true,});// Expo 49 issue: default metro config needs to include "mjs"// https://github.com/expo/expo/issues/23180config.resolver.sourceExts.push('mjs');module.exports = config;
Setup Tamagui
From here on out you can follow the Installation and Configuration docs.
Loading fonts
You need to load your fonts for React Native to recognize them. Typically this looks something like if using Expo, (or you can follow a React Native guide here ):
import { useFonts } from 'expo-font'function App() {const [loaded] = useFonts({Inter: require("@tamagui/font-inter/otf/Inter-Medium.otf"),InterBold: require("@tamagui/font-inter/otf/Inter-Bold.otf"),});useEffect(() => {if (loaded) {// can hide splash screen here}}, [loaded])if (!loaded) {return null;}return <MyApp />}
First time starting Expo
The first time running your project with Tamagui, be sure to clear the cache:
expo start -c
Your package.json
scripts should look something like this:
{"scripts": {"start-native": "expo start -c","start-web": "expo start -c","android": "yarn expo run:android","ios": "yarn expo run:ios","web": "expo start --web"}}
Previous
Next.js
Next
Vite