Installation

How to get Tamagui set up.

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

The instructions here are for using tamagui, a more complete set of components designed to build entire apps out of the box. It's fully tree-shakeable, so your bundler should only add components you import.

If you'd rather build your own design system on top of core, see the Design Systems guide.

Quick Start

Try out create-tamagui-app for a helpful starter template which comes with @tamagui/shorthands and @tamagui/theme-base for easy default shorthands, themes and tokens.

You can also instantly fork the starter repo to your Github and deploy it with Vercel:

Install Tamagui

yarn add tamagui react-native-web
# for web, webpack, only:
yarn add tamagui-loader
# for react-native, only:
yarn add @tamagui/babel-plugin
# react-native wants you to directly add these sub-dependencies
yarn add react-native-safe-area-context

Set up your build

For more information on the options, see the compiler options. Whether using Webpack or Next.js, be sure to not use the Tamagui babel plugin in your web build! They are either-or: the babel plugin only for React Native, and tamagui-loader or next plugin only for web.

Be sure to set the environment variable TAMAGUI_TARGET to "web" or "native" appropriately.

Web

Webpack

We have a full example of a plain, webpack-only repo here , which should capture the complete configuration more accurately.

Add tamagui-loader and set up your webpack.config.js:

const { shouldExclude } = require('tamagui-loader')
const tamaguiOptions = {
config: './tamagui.config.ts',
components: ['tamagui'],
importsWhitelist: ['constants.js', 'colors.js'],
logTimings: true,
disableExtraction: process.env.NODE_ENV === 'development',
}
const projectRoot = __dirname
module.exports = {
module: {
rules: [
{
test: /\.[jt]sx?$/,
// you'll likely want to adjust this helper function,
// but it serves as a decent start that you can copy/paste from
exclude: path => shouldExclude(path, projectRoot, tamaguiOptions),
use: [
// optionally thread-loader for significantly faster compile!
'thread-loader',
// works nicely alongside esbuild
{
loader: 'esbuild-loader',
options: {
loader: 'tsx',
minify: process.env.NODE_ENV === 'production',
},
},
{
loader: 'tamagui-loader',
options: tamaguiOptions,
},
]
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env.TAMAGUI_TARGET': '"web"',
})
]
}
  • importsWhitelist: Tamagui takes a conservative approach to partial evaluation, this field whitelists (matching against both .ts and .js) files to allow files that import them to read and use their values during compilation. Typically colors and constants files.
  • disableExtaction: Useful for faster developer iteration as themes hot reload more reliably.
Next.js

Add @tamagui/next-plugin and configure your next.config.js:

const withPlugins = require('next-compose-plugins')
const { withTamagui } = require('@tamagui/next-plugin')
export default withPlugins([
// All options shows are optional, except config:
withTamagui({
// Path to your tamagui.config.ts file:
config: './tamagui.config.ts',
// Your design system (default: "tamagui")
components: ['tamagui'],
// Follow normalized imports matching these file names, attempt to evaluate
// their exports for static extraction
importsWhitelist: ['constants.js', 'colors.js'],
// display detailed output (default true)
logTimings: true,
// disable static extraction, faster to iterate in dev mode (default false)
disableExtraction: process.env.NODE_ENV === 'development',
// disableExtraction only disables optimizations but keeps the debug ability and output
// if you want faster builds, you can disable tamagui entirely with this (default false)
disable: false,
// Exclude react-native-web modules to lighten bundle
excludeReactNativeWebExports: ['Switch', 'ProgressBar', 'Picker'],
// The following options are for more unusual configurations
// By default, we configure webpack to pass anything inside your root or design system
// to the Tamagui loader. If you are importing files from an external package, use this:
shouldExtract: (path: string, projectRoot: string) => {
if (path.includes('../packages/my-app')) {
return true
}
},
// Many packages give difficulty to the nextjs server-side (node) runtime when un-bundled.
// for example, tamagui configures aliases like `react-native` => `react-native-web`.
// if you're running into a module that has errors importing react-native, you'll want to
// use a custom shouldExcludeFromServer function to include it (or override the default).
// this is the exact same return type as webpack.externals.
// returning undefined will let tamagui handle it, boolean or other values to override.
shouldExcludeFromServer: ({ fullPath, request }) => {
if (fullPath.includes('my-module')) {
return `commonjs ${commonjs}`
}
if (request === 'some-hard-to-bundle-package') {
return true
}
}
})
])

Note: If running into issues, the environment variable IGNORE_TS_CONFIG_PATHS to "true" can fix issues with Tamagui being resolved incorrectly.

See the Next.js Guide for more details on setting up your app.

Native

React Native

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

module.exports = {
plugins: [
[
'@tamagui/babel-plugin',
{
components: ['tamagui'],
config: './tests/lib/tamagui.config.js',
importsWhitelist: ['constants.js', 'colors.js'],
logTimings: true,
disableExtraction: process.env.NODE_ENV === 'development',
}
]
]
}

We've noticed errors in other versions (0.65.5), so you may want to pin @types/react-native to 0.66.6.

You'll also need to configure support for unimodules either using the old method , or using the expo package .

Tamagui uses @expo/match-media and expo-linear-gradient, so you'll want expo installed to support their modules. Add expo-linear-gradient directly to your package.json to fix it not being found by expo.

Expo

Check out the Expo guide for more information on setting up Expo.

Compiler options

The webpack loader and Next.js plugin accept the same configuration options:

Prop

Type

Default

config*
string

Relative path to your tamagui.config.ts file which should export default the result from createTamagui.

components
string[]['tamagui']

Array of npm modules containing Tamagui components which youll be using in your app. For example: if you are using the base Tamagui components. This directs the compiler to load and optimize.

importsWhitelist
string[]

Array of whitelisted file paths (always end in .js) which the compiler may parse at build-time. This usually is like ['constants.js', 'colors.js'], enabling extraction of any constant in those files

logTimings
boolean

Tamagui outputs information for each file it compiles on how long it took to run, how many components it optimized, and how many it flattened. Set to false to disable these logs.

disableExtraction
boolean

Disable extraction to CSS completely, instead fully relying on runtime. Setting this to true speed up development as generally your app will hot reload the Tamagui configuration itself.

disableDebugAttr
boolean

If enabled along with disableExtraction, all parsing will turn off. Normally turning off disableExtraction will keep the helpful debug attributes in DOM

Set up your theme

Create a tamagui.config.js (or ts) file at the root of your project that passes in a theme. For more documentation see Themes.

import { createTamagui } from 'tamagui'
const config = createTamagui({
// Initial theme
defaultTheme: 'light',
// Generates @media(prefers-color-scheme) queries for light/dark
shouldAddPrefersColorThemes: true,
// Shorthand properties
shorthands: {
px: 'paddingHorizontal',
},
// Themes, light/dark are treatest special
themes: {
light: {
bg: '#fff',
color: '#000'
}
},
media: {
xs: { maxWidth: 660 },
gtXs: { minWidth: 660 + 1 },
sm: { maxWidth: 860 },
gtSm: { minWidth: 860 + 1 },
md: { minWidth: 980 },
gtMd: { minWidth: 980 + 1 },
short: { maxHeight: 820 },
tall: { minHeight: 820 },
hoverNone: { hover: 'none' },
pointerCoarse: { pointer: 'coarse' },
},
// ... see Themes docs
tokens: {},
fonts: {},
animations: {},
})
type Conf = typeof config
declare module 'tamagui' {
interface TamaguiCustomConfig extends Conf {}
}
export default config

The createTamagui function receives a configuration object:

  • tokens: Use createTokens to generate variables in your theme and app.
  • theme: Define your design theme, which map to CSS properties.
  • media: Define reusable responsive media queries.
  • shorthands: Define any props you want to expand to style values, keys being the shorthand and values being the expanded style prop.

Set up root

Import and use the Tamagui Provider component at the top component in your app.

import React, { Suspense } from 'react'
import Tamagui from './tamagui.config'
export default function App() {
return (
<Tamagui.Provider>
{/* if you use suspense, you'll want one here */}
<Suspense>
{/* The rest of your app here */}
</Suspense>
</Tamagui.Provider>
)
}

Tamagui.Provider has optional props:

Prop

Type

Default

injectCSS
boolean

When true, injects Tamagui generated CSS into the head on mount.

fallback
boolean

TamaguiProvider wraps Suspense inside to prevent theme flickering, provide a fallback here.

Note, you'll need to handle injecting CSS either through injectCSS, or by gathering it yourself and inserting it:

import Tamagui from './tamagui.config'
const css = Tamagui.getCSS()
// insert into your head

Even when using Webpack, some CSS won't be extracted and so will need to come from this helper.

Finally, you may want to reset your CSS on your web app, we provide a very minimal one you can import. For Next.js apps, do so at the top of your _app.tsx:

import '@tamagui/core/reset.css'

Use any views

You're now ready to use Tamagui, import and use any components:

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

Web-only configurations

If you want autocompleted imports of react-native without having to install all the weight of react-native, you can set react-native version to 0.0.0, and add @types/react-native at the latest version.