wwwwwwwwwwwwwwwwwww

Installation

How to get Tamagui set up.

Tamagui is a full-featured UI kit built on top of @tamagui/core.

If you want a complete set of components designed to build universal apps, use tamagui. If you want to build out your own components and don't want any of the tamagui components, you can just use @tamagui/core. See the Design Systems guide for more on how to configure Core.

This document uses tamagui as an example, but if you are using @tamagui/core you can swap out the import.

Saving bundle size for web-only use cases

If you are only targeting the web: @tamagui/web is the same library as @tamagui/core, except that it drops support for a few React Native specific things, mostly props: namely the GestureResponderHandlers and onLayout props are absent, and the platform methods on refs like measureInWindow are absent. If you are only targeting web, you can swap every reference of tamagui or @tamagui/core in this guide with @tamagui/web. Note that you can't use @tamagui/web with tamagui as the full tamagui package relies on many of these props.

Quick Start

Try out create-tamagui for a helpful starter template which comes with @tamagui/shorthands and @tamagui/themes for easy default configuration:

npm create tamagui@latest

This gives you everything pre-configured for full-stack apps with shared code.

Install

yarn add tamagui

You generally need to configure one or two things: passing the environment variable TAMAGUI_TARGET (set to the string web or native, respectively), and on the web, setting an alias from react-native to react-native-web.

Web

To pass the ENV you add it to the beginning of your start script generally like so:

{
"scripts": {
"dev": "TAMAGUI_TARGET=web webpack"
}
}

Tamagui has plugins that make the rest a bit simpler to set up (and also get you the optimizing compiler) which you can find in the Compiler Install docs.

You just want to ensure two things happen: the TAMAGUI_TARGET environment variable is passed in, and react-native is aliased to react-native-web (only if using tamagui or other React Native APIs yourself, as core it doesn't have a dependency on react-native at all).

Webpack

We also recommend passing in __DEV__ and NODE_ENV if using react-native:

Show more
config.plugins.push(
new webpack.DefinePlugin({
process: {
env: {
TAMAGUI_TARGET: JSON.stringify('web'),
DEV: process.env.NODE_ENV === 'development' ? 'true' : 'false',
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
},
},
})
)
config.resolve.alias['react-native$'] = 'react-native-web'
// or react-native-web-lite if using our more modern but less supported version
// set up web extensions
compiler.options.resolve.extensions = [
'.web.tsx',
'.web.ts',
'.web.js',
'.ts',
'.tsx',
'.js',
]

Vite

Show more
config.define = {
DEV: `${process.env.NODE_ENV === 'development' ? true : false}`,
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'process.env.TAMAGUI_TARGET': JSON.stringify('web'),
}
config.resolve.alias['react-native'] = 'react-native-web'
// or react-native-web-lite if using our more modern but less supported version
// set up web extensions
config.optimizeDeps.esbuildOptions = {
...config.optimizeDeps.esbuildOptions,
resolveExtensions: [
'.web.js',
'.web.ts',
'.web.tsx',
'.js',
'.jsx',
'.json',
'.ts',
'.tsx',
'.mjs',
],
loader: {
'.js': 'jsx',
},
}

Native

Babel

For native you'd do something like this:

TAMAGUI_TARGET=native react-native start
TAMAGUI_TARGET=native expo start

You'll also need to indicate to Metro and babel to inline TAMAGUI_TARGET like so:

yarn add @tamagui/babel-plugin babel-plugin-transform-inline-environment-variables

Add @tamagui/babel-plugin to your babel.config.js plugins:

// just to ensure TAMAGUI_TARGET is set
process.env.TAMAGUI_TARGET = 'native'
module.exports = {
plugins: [
['transform-inline-environment-variables', {
include: ['TAMAGUI_TARGET']
}]
]
}

Media Queries

This is also documented in Configuration, but worth noting twice.

@tamagui/core doesn't provide media capabilities out of the box to native apps, while on the web it uses native media queries. To enable media queries for React Native, you need to provide matchMedia implementation:

yarn add @tamagui/react-native-media-driver
import { createMedia } from '@tamagui/react-native-media-driver'
export default createTamagui({
media: createMedia({
xs: { maxWidth: 660 },
// ...
}),
})

Config file

Create a tamagui.config.ts file at the root of your project. You can import createTamagui from either tamagui or @tamagui/core depending on which you decide to use.

From there you'll export default the result of createTamagui like so:

Show more
import { shorthands } from '@tamagui/shorthands'
import { themes, tokens } from '@tamagui/themes'
import { createFont, createTamagui } from 'tamagui'
export default createTamagui({
themes,
tokens,
shorthands,
fonts: {
body: createFont({
family: 'Arial',
size: {
// You'll want to fill these values in so you can use them
// for now, fontSize="$4" will be 14px.
// You can define different keys, but `tamagui`
// standardizes on 1-15.
4: 14,
},
lineHeight: {
4: 16,
},
}),
},
})

You'll need to install these packages if you want the Tamagui pre-configured design system:

yarn add @tamagui/shorthands @tamagui/themes

For an even quicker start, you can get a full design system with @tamagui/config, which we show on the Configuration page. That page also goes into more detail on everything createTamagui accepts.

Root export

Import and use the TamaguiProvider component as the top component in your app.

// this provides some helpful reset styles to ensure a more consistent look
// only import this from your web app, not native
import '@tamagui/core/reset.css'
import React, { Suspense } from 'react'
import { TamaguiProvider } from 'tamagui'
import config from './tamagui.config'
export default function App() {
return (
<TamaguiProvider config={config}>
{/* if you want nice React 18 concurrent hydration, you'll want Suspense near the root */}
<Suspense>
<AppContents />
</Suspense>
</TamaguiProvider>
)
}

TamaguiProvider has optional props, see the docs for them here.

Webpack, Vite and other web bundlers

Each bundler has a plugin that helps automate setup. See these docs for more:

For a minimal install without any compiler setup, you'll just need to alias react-native to react-native-web (or react-native-web-lite if you're feeling adventurous and want better concurrent mode support and a more up to date RN Animated driver).

For Webpack:

config.resolve.alias['react-native$'] = require.resolve('react-native-web')

Or alternatively, to react-native-web-lite, our more experimental but modern version of react-native-web.

Other bundlers and frameworks

Remember, Tamagui runs fully at runtime, so you don't need to set up the compiler to start. But because Tamagui imports react-native directly, for web platforms you need to configure an alias. And for CSS extraction, on some frameworks like Next.js require extra configuration.

We have a few guides for the compiler that also include setup of any extras for the web:

Just note: you don't need to set up the compiler!

For the web you usually just need to alias react-native to react-native-web if you are using @tamagui/core or tamagui. If you are using the lowest level @tamagui/web package, which is basically core but without the React Native unified event APIs, you don't need anything else as it doesn't rely on react-native at all.

Done!

You're ready to use Tamagui:

Hello world
import { Button } from 'tamagui'
export default function Demo() {
return <Button>Button</Button>
}

We recommend spending time understanding configuration from here, skipping over the Compiler setup. The compiler is optional and should be saved for setting up after you've built something you'd like to test it with.