/tamagui
Universal React UI framework for web and native. Use when building cross-platform apps with Tamagui, creating styled components with `styled()`, configuring design tokens/themes, using Tamagui UI components, or working with animations. Triggers: "tamagui", "styled()", "$token",
$ npx -y skills add tamagui/tamagui --skill tamagui --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/tamagui
Context preview
The summary Claude sees to decide when to auto-load this skill.
Universal React UI framework for web and native. Use when building cross-platform apps with Tamagui, creating styled components with `styled()`, configuring design tokens/themes, using Tamagui UI components, or working with animations. Triggers: "tamagui", "styled()", "$token",
SKILL.md
tamagui.SKILL.mdname: tamagui
description: |
Universal React UI framework for web and native. Use when building cross-platform apps with Tamagui,
creating styled components with `styled()`, configuring design tokens/themes, using Tamagui UI components,
or working with animations. Triggers: "tamagui", "styled()", "$token", "XStack/YStack", "useTheme",
"@tamagui/*" imports, "createStyledContext", "variants".
version: 1.0.0
Tamagui Skill
Universal React UI framework for web and native with an optimizing compiler.
Getting Project-Specific Config
**Before writing Tamagui code**, get the project's actual configuration:
npx tamagui generate-prompt
This outputs `tamagui-prompt.md` with the project's specific:
- Design tokens (space, size, radius, color, zIndex)
- Theme names and hierarchy
- Available components
- Media query breakpoints
- Shorthand properties
- Font families
**Always reference this file for token/theme/media query names** rather than guessing or using defaults.
---
Core Concepts
styled() Function
Create components by extending existing ones:
import { View, Text, styled } from '@tamagui/core'
const Card = styled(View, {
padding: '$4', // use tokens with $
backgroundColor: '$background',
borderRadius: '$4',
variants: {
size: {
small: { padding: '$2' },
large: { padding: '$6' },
},
elevated: {
true: {
shadowColor: '$shadowColor',
shadowRadius: 10,
},
},
} as const, // required for type inference
defaultVariants: {
size: 'small',
},
})
// usage
<Card size="large" elevated />**Key rules:**
- Always use `as const` on variants objects
- Tokens use `$` prefix: `$4`, `$background`, `$color11`
- Prop order matters - later props override earlier ones
- Variants defined later in the object override earlier ones
Stack Components
import { XStack, YStack, ZStack } from 'tamagui'
// XStack = flexDirection: 'row'
// YStack = flexDirection: 'column'
// ZStack = position: 'relative' with absolute children
<YStack gap="$4" padding="$4">
<XStack justifyContent="space-between" alignItems="center">
<Text>Label</Text>
<Button>Action</Button>
</XStack>
</YStack>Themes
Themes nest and combine hierarchically:
import { Theme } from 'tamagui'
// base theme
<Theme name="dark">
{/* sub-theme */}
<Theme name="blue">
{/* uses dark_blue theme */}
<Button>Blue button on dark</Button>
</Theme>
</Theme>
// access theme values
const theme = useTheme()
console.log(theme.background.val) // actual color value
console.log(theme.color11.val) // high contrast text**12-step color scale convention:**
- `$color1-4`: backgrounds (subtle to emphasized)
- `$color5-6`: borders, separators
- `$color7-8`: hover/active states
- `$color9-10`: solid backgrounds
- `$color11-12`: text (low to high contrast)
Responsive Styles
Use media query props (check your `tamagui-prompt.md` for actual breakpoint names):
<YStack
padding="$4"
$gtSm={{ padding: '$6' }} // check your config for actual names
$gtMd={{ padding: '$8' }}
flexDirection="column"
$gtLg={{ flexDirection: 'row' }}
/>
// or with hook
const media = useMedia()
if (media.gtMd) {
// render for medium+ screens
}Animations
import { AnimatePresence } from 'tamagui'
<AnimatePresence>
{show && (
<YStack
key="modal" // key required for exit animations
animation="quick"
enterStyle={{ opacity: 0, y: -20 }}
exitStyle={{ opacity: 0, y: 20 }}
opacity={1}
y={0}
/>
)}
</AnimatePresence>**Animation drivers:**
- `@tamagui/animations-css` - web only, CSS transitions
- `@tamagui/animations-react-native` - native Animated API
- `@tamagui/animations-reanimated` - best native performance
- `@tamagui/animations-motion` - spring physics
CSS driver uses easing strings, others support spring physics.
---
Compound Components
Use `createStyledContext` for components that share state:
import { createStyledContext, styled, View, Text } from '@tamagui/core'
import { withStaticProperties } from '@tamagui/helpers'
const CardContext = createStyledContext({ size: 'medium' as 'small' | 'medium' | 'large' })
const CardFrame = styled(View, {
context: CardContext,
padding: '$4',
backgroundColor: '$background',
variants: {
size: {
small: { padding: '$2' },
medium: { padding: '$4' },
large: { padding: '$6' },
},
} as const,
})
const CardTitle = styled(Text, {
context: CardContext, // inherits size from parent
fontWeight: 'bold',
variants: {
size: {
small: { fontSize: '$4' },
medium: { fontSize: '$5' },
large: { fontSize: '$6' },
},
} as const,
})
export const Card = withStaticProperties(CardFrame, {
Title: CardTitle,
})
// usage - size cascades to children
<Card size="large">
<Card.Title>Large Title</Card.Title>
</Card>---
Common Patterns
Dialog with Adapt (Sheet on Mobile)
import { Dialog, Sheet, Adapt, Button } from 'tamagui'
<Dialog>
<Dialog.Trigger asChild>
<Button>Open</Button>
</Dialog.Trigger>
<Adapt when="sm" platform="touch">
<Sheet modal dismissOnSnapToBottom>
<Sheet.Frame padding="$4">
<Adapt.Contents />
</Sheet.Frame>
<Sheet.Overlay />
</Sheet>
</Adapt>
<Dialog.Portal>
<Dialog.Overlay
key="overlay"
animation="quick"
opacity={0.5}
enterStyle={{ opacity: 0 }}
exitStyle={{ opacity: 0 }}
/>
<Dialog.Content
key="content"
animation="quick"
enterStyle={{ opacity: 0, scale: 0.95 }}
exitStyle={{ opacity: 0, scale: 0.95 }}
>
<Dialog.Title>Title</Dialog.Title>
<Dialog.Description>Description</Dialog.Description>
<Dialog.Close asChild>
<Button>Close</Button>
</Dialog.Close>
</Dialog.Content>
</Dialog.Portal>
</Dialog>Form with Inp
Read more
name: tamagui description: | Universal React UI framework for web and native. Use when building cross-platform apps with Tamagui, creating styled components with `styled()`, configuring design tokens/themes, using Tamagui UI components, or working with animations. Triggers: "tamagui", "styled()", "$token", "XStack/YStack", "useTheme", "@tamagui/*" imports, "createStyledContext", "variants". version: 1.0.0
Tamagui Skill
Universal React UI framework for web and native with an optimizing compiler.
Getting Project-Specific Config
**Before writing Tamagui code**, get the project's actual configuration:
npx tamagui generate-prompt
This outputs `tamagui-prompt.md` with the project's specific:
- Design tokens (space, size, radius, color, zIndex)
- Theme names and hierarchy
- Available components
- Media query breakpoints
- Shorthand properties
- Font families
**Always reference this file for token/theme/media query names** rather than guessing or using defaults.
---
Core Concepts
styled() Function
Create components by extending existing ones:
import { View, Text, styled } from '@tamagui/core'
const Card = styled(View, {
padding: '$4', // use tokens with $
backgroundColor: '$background',
borderRadius: '$4',
variants: {
size: {
small: { padding: '$2' },
large: { padding: '$6' },
},
elevated: {
true: {
shadowColor: '$shadowColor',
shadowRadius: 10,
},
},
} as const, // required for type inference
defaultVariants: {
size: 'small',
},
})
// usage
<Card size="large" elevated />**Key rules:**
- Always use `as const` on variants objects
- Tokens use `$` prefix: `$4`, `$background`, `$color11`
- Prop order matters - later props override earlier ones
- Variants defined later in the object override earlier ones
Stack Components
import { XStack, YStack, ZStack } from 'tamagui'
// XStack = flexDirection: 'row'
// YStack = flexDirection: 'column'
// ZStack = position: 'relative' with absolute children
<YStack gap="$4" padding="$4">
<XStack justifyContent="space-between" alignItems="center">
<Text>Label</Text>
<Button>Action</Button>
</XStack>
</YStack>Themes
Themes nest and combine hierarchically:
import { Theme } from 'tamagui'
// base theme
<Theme name="dark">
{/* sub-theme */}
<Theme name="blue">
{/* uses dark_blue theme */}
<Button>Blue button on dark</Button>
</Theme>
</Theme>
// access theme values
const theme = useTheme()
console.log(theme.background.val) // actual color value
console.log(theme.color11.val) // high contrast text**12-step color scale convention:**
- `$color1-4`: backgrounds (subtle to emphasized)
- `$color5-6`: borders, separators
- `$color7-8`: hover/active states
- `$color9-10`: solid backgrounds
- `$color11-12`: text (low to high contrast)
Responsive Styles
Use media query props (check your `tamagui-prompt.md` for actual breakpoint names):
<YStack
padding="$4"
$gtSm={{ padding: '$6' }} // check your config for actual names
$gtMd={{ padding: '$8' }}
flexDirection="column"
$gtLg={{ flexDirection: 'row' }}
/>
// or with hook
const media = useMedia()
if (media.gtMd) {
// render for medium+ screens
}Animations
import { AnimatePresence } from 'tamagui'
<AnimatePresence>
{show && (
<YStack
key="modal" // key required for exit animations
animation="quick"
enterStyle={{ opacity: 0, y: -20 }}
exitStyle={{ opacity: 0, y: 20 }}
opacity={1}
y={0}
/>
)}
</AnimatePresence>**Animation drivers:**
- `@tamagui/animations-css` - web only, CSS transitions
- `@tamagui/animations-react-native` - native Animated API
- `@tamagui/animations-reanimated` - best native performance
- `@tamagui/animations-motion` - spring physics
CSS driver uses easing strings, others support spring physics.
---
Compound Components
Use `createStyledContext` for components that share state:
import { createStyledContext, styled, View, Text } from '@tamagui/core'
import { withStaticProperties } from '@tamagui/helpers'
const CardContext = createStyledContext({ size: 'medium' as 'small' | 'medium' | 'large' })
const CardFrame = styled(View, {
context: CardContext,
padding: '$4',
backgroundColor: '$background',
variants: {
size: {
small: { padding: '$2' },
medium: { padding: '$4' },
large: { padding: '$6' },
},
} as const,
})
const CardTitle = styled(Text, {
context: CardContext, // inherits size from parent
fontWeight: 'bold',
variants: {
size: {
small: { fontSize: '$4' },
medium: { fontSize: '$5' },
large: { fontSize: '$6' },
},
} as const,
})
export const Card = withStaticProperties(CardFrame, {
Title: CardTitle,
})
// usage - size cascades to children
<Card size="large">
<Card.Title>Large Title</Card.Title>
</Card>---
Common Patterns
Dialog with Adapt (Sheet on Mobile)
import { Dialog, Sheet, Adapt, Button } from 'tamagui'
<Dialog>
<Dialog.Trigger asChild>
<Button>Open</Button>
</Dialog.Trigger>
<Adapt when="sm" platform="touch">
<Sheet modal dismissOnSnapToBottom>
<Sheet.Frame padding="$4">
<Adapt.Contents />
</Sheet.Frame>
<Sheet.Overlay />
</Sheet>
</Adapt>
<Dialog.Portal>
<Dialog.Overlay
key="overlay"
animation="quick"
opacity={0.5}
enterStyle={{ opacity: 0 }}
exitStyle={{ opacity: 0 }}
/>
<Dialog.Content
key="content"
animation="quick"
enterStyle={{ opacity: 0, scale: 0.95 }}
exitStyle={{ opacity: 0, scale: 0.95 }}
>
<Dialog.Title>Title</Dialog.Title>
<Dialog.Description>Description</Dialog.Description>
<Dialog.Close asChild>
<Button>Close</Button>
</Dialog.Close>
</Dialog.Content>
</Dialog.Portal>
</Dialog>Form with Inp
Style React fast with 100% parity on React Native, an optional UI kit, and optimizing compiler.
Repo: tamagui/tamagui
Other skills on tamagui.
- /git-safety
Git safety rules. INVOKE WHEN: git push, force push, git reset, git clean, destructive git, push force, reset hard. NEVER force push or do destructive git operations.
Open skill - /release-safety
Release safety rules. INVOKE WHEN: yarn release, npm publish, release canary, release packages, publishing, skip checks, skip tests. NEVER skip checks or tests without explicit permission.
Open skill

