Tamagui
Sistema de diseño multiplataforma con compilación de estilos optimizada.
Busca en todas las páginas de la documentación
Sistema de diseño multiplataforma con compilación de estilos optimizada.
Tamagui es un sistema de diseño universal para React Native (y web): tokens tipados, primitivos estilizados (Stack, Text, Button) y un compilador que aplana props de estilos en objetos optimizados. En Expo SDK 57, es adecuado para equipos que quieren disciplina de componentes + tokens más allá de clases de utilidad - con rendimiento ajustado para aplicaciones pesadas en listas.
Tarjeta de receta de referencia rápida - lista para copiar y pegar.
npx create-expo-app@latest MyTamaguiApp --template blank-typescript
cd MyTamaguiApp
npx expo install tamagui @tamagui/config @tamagui/core react-native-reanimated react-native-safe-area-context// tamagui.config.ts
import { config as defaultConfig } from "@tamagui/config";
import { createTamagui } from "tamagui";
export const config = createTamagui({
...defaultConfig,
tokens: {
...defaultConfig.tokens,
color: {
...defaultConfig.tokens.color,
brand: "#2563eb",
brandMuted: "#93c5fd",
},
},
themes: {
...defaultConfig.themes,
light: {
...defaultConfig.themes.light,
brand: "#2563eb",
},
dark: {
...defaultConfig.themes.dark,
brand: "#60a5fa",
},
},
});
export type AppConfig = typeof config;
declare module "tamagui" {
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
interface TamaguiCustomConfig extends AppConfig {}
}// App.tsx
import { TamaguiProvider, Theme, YStack, Text, Button } from "tamagui";
import { useColorScheme } from "react-native";
import { config } from "./tamagui.config";
export default function App() {
const scheme = useColorScheme() ?? "light";
return (
<TamaguiProvider config={config} defaultTheme={scheme}>
<Theme name={scheme}>
<YStack flex={1} padding="$4" backgroundColor="$background" gap="$3">
<Text fontSize="$6" fontWeight="700" color="$color">
Tamagui en Expo
</Text>
<Button theme="active" backgroundColor="$brand" color="white">
Continuar
</Button>
</YStack>
</Theme>
</TamaguiProvider>
);
}{
"expo": {
"plugins": ["react-native-reanimated/plugin"]
}
}Cuándo usar esto:
size="$4", color="$brand") con validación en tiempo de compilación.Button, Card) en lugar de solo clases de utilidad.Tarjeta de producto con variantes, tema oscuro y una fila de lista memoizada construida sobre tokens de Tamagui.
// components/ProductCard.tsx
import { Card, H4, Paragraph, XStack, YStack, styled } from "tamagui";
const Badge = styled(Paragraph, {
name: "Badge",
fontSize: "$1",
fontWeight: "700",
paddingHorizontal: "$2",
paddingVertical: "$1",
borderRadius: "$10",
variants: {
tone: {
sale: { backgroundColor: "$red4", color: "$red11" },
new: { backgroundColor: "$green4", color: "$green11" },
},
} as const,
defaultVariants: { tone: "new" },
});
type Props = {
title: string;
price: string;
badge?: "sale" | "new";
};
export function ProductCard({ title, price, badge = "new" }: Props) {
return (
<Card elevate bordered padding="$4" backgroundColor="$background">
<YStack gap="$2">
<XStack justifyContent="space-between" alignItems="center">
<H4 color="$color" numberOfLines={1}>
{title}
</H4>
{badge && <Badge tone={badge}>{badge === "sale" ? "OFERTA" : "NUEVA"}</Badge>}
</XStack>
<Paragraph color="$color11" fontSize="$5" fontWeight="600">
{price}
</Paragraph>
</YStack>
</Card>
);
}// screens/CatalogScreen.tsx
import { FlatList } from "react-native";
import { YStack, Text } from "tamagui";
import { ProductCard } from "../components/ProductCard";
const PRODUCTS = [
{ id: "1", title: "Trail Runner Pro", price: "$129", badge: "new" as const },
{ id: "2", title: "Merino Base Layer", price: "$79", badge: "sale" as const },
{ id: "3", title: "Softshell Jacket", price: "$199", badge: "new" as const },
];
export function CatalogScreen() {
return (
<YStack flex={1} padding="$4" backgroundColor="$background" gap="$3">
<Text fontSize="$8" fontWeight="800" color="$color">
Catálogo
</Text>
<FlatList
data={PRODUCTS}
keyExtractor={(item) => item.id}
ItemSeparatorComponent={() => <YStack height="$3" />}
renderItem={({ item }) => (
<ProductCard title={item.title} price={item.price} badge={item.badge} />
)}
/>
</YStack>
);
}// app/_layout.tsx
import { TamaguiProvider, Theme } from "tamagui";
import { Slot } from "expo-router";
import { useColorScheme } from "react-native";
import { config } from "../tamagui.config";
export default function RootLayout() {
const scheme = useColorScheme() ?? "light";
return (
<TamaguiProvider config={config} defaultTheme={scheme}>
<Theme name={scheme}>
<Slot />
</Theme>
</TamaguiProvider>
);
}Lo que esto demuestra:
$ - $4 se resuelve en el token de espaciado 4 de la configuración.styled() con variants - tone="sale" se asigna a colores conscientes del tema, no valores hexadecimales en línea.Theme name={scheme} cambia objetos de tema claro/oscuro desde tamagui.config.ts.Card elevate bordered - las props abreviadas de Tamagui se compilan a elevación apropiada para la plataforma.createTamagui fusiona tus tokens, temas, fuentes y media en un único objeto de configuración.TamaguiProvider suministra la configuración y el tema activo al árbol de React.padding="$4" a valores numéricos en compilación/runtime y aplanan a objetos de estilo de RN.light, dark). Los componentes hacen referencia a $color, $background, no hex codificado.@tamagui/compiler o plugin de Babel) puede optimizar aún más árboles estáticos - evalúa cuando el tamaño del bundle es importante.| Capa | Ejemplo | Propósito |
|---|---|---|
tokens.color.brand | #2563eb | Paleta cruda |
themes.light.brand | #2563eb | Función específica del tema |
| Prop del componente | backgroundColor="$brand" | Consumo en JSX |
declare module "tamagui" {
interface TamaguiCustomConfig extends AppConfig {}
}$ y nombres de variantes.as const en objetos variants para que tone sea "sale" | "new", no string.AppConfig desde tamagui.config.ts para decoradores de Storybook que necesitan temas tipados.Algunos paquetes opcionales de Tamagui necesitan resolución explícita. Si Metro falla en subrutas @tamagui/*:
// metro.config.js
const { getDefaultConfig } = require("expo/metro-config");
const config = getDefaultConfig(__dirname);
config.resolver.unstable_enablePackageExports = true;
module.exports = config;Ejecuta npx expo start --clear después de agregar Tamagui a un proyecto existente.
TamaguiProvider faltante - los tokens $ se resuelven a estilos indefinidos. Solución: Envuelve el layout raíz, en la misma ubicación que otros proveedores de temas.
Desajuste de nombre de tema - Theme name="dark" sin una clave dark en themes. Solución: Bifurca temas de @tamagui/config o define tanto light como dark.
Mezclar Tamagui y View crudo - el ritmo de espaciado se quiebra. Solución: Utiliza YStack/XStack para islas de layout; migra incrementalmente.
Hex en línea en componentes Tamagui - anula la tematización. Solución: Agrega entrada de token + tema, referencia $brand.
Orden del plugin Reanimated - el plugin Babel de Reanimated debe ser último en babel.config.js. Solución: Sigue los documentos de Expo Reanimated cuando habilitas animaciones junto con Tamagui.
Props solo para web en nativo - algunas props abreviadas se dirigen a CSS web. Solución: Prueba en ambas plataformas; utiliza Platform.select en componentes estilizados personalizados cuando sea necesario.
| Alternativa | Úsalo Cuando | No lo Úses Cuando |
|---|---|---|
| Tamagui | Componentes tipados por tokens + uso compartido web | El equipo quiere solo cadenas de Tailwind |
| NativeWind | Ergonomía de clase de utilidad | Necesitas APIs de variantes de primera clase en primitivos |
| React Native Paper | Material Design listo para usar | Lenguaje de marca altamente personalizado |
| StyleSheet + tokens | Dependencias mínimas | Gran DS con muchas matrices de variantes |
| @expo/ui | Chrome nativo de SwiftUI/Compose | Lenguaje de diseño personalizado no relacionado con widgets de plataforma |
Sí. Instala tamagui, @tamagui/config y react-native-reanimated a través de npx expo install. Envuelve la app en TamaguiProvider y carga tamagui.config.ts en el layout raíz.
$4 hace referencia al token de espacio 4. $color hace referencia al rol de color del tema activo. Es la abreviatura de Tamagui para búsqueda de tokens - no es una cadena literal.
Expande defaultConfig desde @tamagui/config, anula tokens y themes, y mantén tipos de createTamagui a través de ampliación de módulos. No copies ciegamente el tema predeterminado completo - recorta tokens no utilizados para reducir el tamaño del bundle.
NativeWind asigna clases de Tailwind a estilos. Tamagui proporciona componentes estilizados + tokens con un sistema de variantes. Los equipos alérgicos a className a menudo prefieren Tamagui; los equipos que vienen de Tailwind web a menudo prefieren NativeWind.
Define light y dark en themes, envuelve con <Theme name={scheme}>, y conduce scheme desde useColorScheme. Ver Dark Mode & Color Schemes.
Sí. Mantén renderItem ligero; extrae ProductCard como un componente separado. Evita crear nuevos objetos de estilo en línea en el callback de renderizado.
Los componentes de Tamagui reenvían props a primitivos de RN - establece accessibilityRole, accessibilityLabel, y prueba con VoiceOver/TalkBack. Ver Accessibility Basics.
Stack versions: Esta página fue escrita para React 19.2.3, React Native 0.86.0, y Expo SDK 57 (
expo~57.0.4).
Revisado por Chris St. John·Última actualización: 19 jul 2026