Tamagui Troubleshooting Guide
Overview
This document captures the issues we encountered with Tamagui and how we solved them. It's a reference for future developers who might run into similar problems.
Issues We Encountered
1. Theme Tokens Not Working ($primary, $secondary, etc.)
Problem:
- Custom theme tokens like
$primarywere undefined or not applying - Nested token references (
primary: "$color6") weren't resolving properly
Root Cause:
- Tamagui's palette system with
createThemeswas over-engineered for our needs - Nested token references caused resolution issues
Solution:
- Hardcode the color values directly in the theme instead of using palette references
- Use direct HSL values:
primary: "hsla(239, 84%, 67%, 1)"
Working Config:
themes: {
light: {
...themes.light,
primary: "hsla(239, 84%, 67%, 1)", // Direct value
secondary: "hsla(230, 94%, 82%, 1)", // Direct value
// etc...
}
}
2. Inconsistent Prop Names (bg vs background)
Problem:
backgroundColorcaused TypeScript errorsbgworked in some contexts but not others- Inconsistent behavior between Tamagui components
Solution:
- Always use
background(notbackgroundColororbg) - This is the canonical Tamagui prop name
Working Example:
<Button background="$primary">Works</Button>
<YStack background="$secondary">Also works</YStack>
3. Custom Button Component Issues
Problem:
- Custom Button component wasn't properly inheriting Tamagui's theme system
- Theme tokens weren't available in custom styled components
Solution:
- Ensure custom components extend Tamagui's base components properly
- Use
styled()with the correct base component
Working Example:
const StyledButton = styled(TamaguiButton, {
name: "Button",
variants: {
link: {
true: {
background: "$primary", // Use theme tokens
color: "$color12",
},
},
},
})
Best Practices (What Actually Works)
1. Theme Configuration
// ✅ DO: Use direct color values
primary: "hsla(239, 84%, 67%, 1)"
// ❌ DON'T: Use nested references
primary: "$color6"
2. Component Props
// ✅ DO: Use canonical Tamagui props
<Button background="$primary" color="$color12">
// ❌ DON'T: Use React Native props
<Button backgroundColor="$primary">
3. Custom Components
// ✅ DO: Extend Tamagui components
const MyButton = styled(TamaguiButton, { ... })
// ❌ DON'T: Create from scratch
const MyButton = styled(View, { ... })
Common Pitfalls
1. Palette System Complexity
- Tamagui's
createThemeswith palettes is over-engineered for most apps - Stick to simple theme objects with direct color values
2. Token Resolution Issues
- Nested token references (
$primary: "$color6") often don't work - Use direct color values instead
3. Prop Name Confusion
backgroundis the correct prop (notbackgroundColororbg)- Check Tamagui's type definitions for the right prop names
4. Custom Component Inheritance
- Custom components must properly extend Tamagui base components
- Don't create components from scratch if you want theme support
Debugging Tips
1. Check Theme Object
const theme = useTheme()
console.log("Theme object:", theme)
console.log("Theme keys:", Object.keys(theme))
2. Test Direct Values
// Test if the component works with direct values
<Button background="#6366f1">Test</Button>
// Then test with theme tokens
<Button background="$primary">Test</Button>
3. Clear Caches
expo start -c
Our Final Working Setup
1. Config Structure
// tamagui.config.ts
const config = {
...defaultConfig,
themes: {
...defaultConfig.themes,
light: {
...themes.light,
primary: "hsla(239, 84%, 67%, 1)",
secondary: "hsla(230, 94%, 82%, 1)",
// ... other semantic colors
},
},
defaultTheme: "light",
}
2. Usage in Components
// ✅ This works
<Button background="$primary" onPress={handlePress}>
<Text color="white">Click me</Text>
</Button>
<YStack background="$background" padding="$4">
<Text color="$color">Content</Text>
</YStack>
Conclusion
Tamagui is powerful but can be frustratingly complex. For most apps, simple is better:
- Use direct color values in themes
- Stick to canonical prop names
- Extend existing Tamagui components
- Don't over-engineer with palettes unless you really need them
Remember: A working, simple solution is better than a broken, complex one.
References
- Tamagui Docs
- [Our Working Config] check../tamagui.config.ts
- [Our Custom Button] check ../app/components/Button.tsx