skillby 0xBigBoss

tamagui-best-practices

Provides Tamagui patterns for config v4, compiler optimization, styled context, and cross-platform styling. Must use when working with Tamagui projects (tamagui.config.ts, @tamagui imports).

Installs: 0
Used in: 1 repos
Updated: 1d ago
$npx ai-builder add skill 0xBigBoss/tamagui-best-practices

Installs to .claude/skills/tamagui-best-practices/

This skill provides patterns for Tamagui v1.x that go beyond fundamentals. It focuses on Config v4, compiler optimization, compound components, and common mistakes.

## Mandatory Context Loading

When working with these components, read the corresponding pattern file BEFORE writing code:

| Component Type | Required Reading | Cross-Skills |
|---------------|------------------|--------------|
| Dialog, Sheet, modal overlays | @DIALOG_PATTERNS.md | |
| Form, Input, Label, validation | @FORM_PATTERNS.md | `typescript-best-practices` (zod) |
| Animations, transitions | @ANIMATION_PATTERNS.md | |
| Popover, Tooltip, Select | @OVERLAY_PATTERNS.md | |
| Compiler optimization | @COMPILER_PATTERNS.md | |
| Design tokens, theming | @DESIGN_SYSTEM.md | |

## Config v4 Quick Start

Use `@tamagui/config/v4` for simplified setup:

```tsx
// tamagui.config.ts
import { defaultConfig } from '@tamagui/config/v4'
import { createTamagui } from 'tamagui'

export const config = createTamagui(defaultConfig)

type CustomConfig = typeof config

declare module 'tamagui' {
  interface TamaguiCustomConfig extends CustomConfig {}
}
```

**Recommended setting** for new projects (aligns flexBasis to React Native):
```tsx
export const config = createTamagui({
  ...defaultConfig,
  settings: {
    ...defaultConfig.settings,
    styleCompat: 'react-native',
  },
})
```

### createThemes Pattern

For custom themes, use `createThemes` with palette/accent/childrenThemes:

```tsx
import { createThemes, defaultComponentThemes } from '@tamagui/config/v4'

const generatedThemes = createThemes({
  componentThemes: defaultComponentThemes,
  base: {
    palette: {
      dark: ['#050505', '#151515', /* ...12 colors */ '#fff'],
      light: ['#fff', '#f8f8f8', /* ...12 colors */ '#000'],
    },
    extra: {
      light: { ...Colors.blue, shadowColor: 'rgba(0,0,0,0.04)' },
      dark: { ...Colors.blueDark, shadowColor: 'rgba(0,0,0,0.2)' },
    },
  },
  accent: {
    palette: { dark: lightPalette, light: darkPalette }, // inverted
  },
  childrenThemes: {
    blue: { palette: { dark: Object.values(Colors.blueDark), light: Object.values(Colors.blue) } },
    red: { /* ... */ },
    green: { /* ... */ },
  },
})
```

## Token and Theme Syntax

### $ Prefix Rules

- **Props**: Use `$` prefix for token references: `<Text color="$color" fontSize="$4" />`
- **Theme keys**: Access without `$` in theme definitions: `{ color: palette[11] }`
- **Token access in variants**: Use `tokens.size[name]` pattern

### Variant Spread Operators

Special spread operators map token categories to variant values:

```tsx
const Button = styled(View, {
  variants: {
    size: {
      // Maps size tokens: $1, $2, $true, etc.
      '...size': (size, { tokens }) => ({
        height: tokens.size[size] ?? size,
        borderRadius: tokens.radius[size] ?? size,
        gap: tokens.space[size]?.val * 0.2,
      }),
    },
    textSize: {
      // Maps fontSize tokens
      '...fontSize': (name, { font }) => ({
        fontSize: font?.size[name],
      }),
    },
  } as const,
})
```

**Important**: Use `as const` on variants object until TypeScript supports inferred const generics.

## Compound Components with createStyledContext

For compound APIs like `<Button><Button.Text>Click</Button.Text></Button>`:

```tsx
import {
  SizeTokens,
  View,
  Text,
  createStyledContext,
  styled,
  withStaticProperties,
} from '@tamagui/core'

// 1. Create context with shared variant types
export const ButtonContext = createStyledContext<{ size: SizeTokens }>({
  size: '$medium',
})

// 2. Create frame with context
export const ButtonFrame = styled(View, {
  name: 'Button',
  context: ButtonContext,
  variants: {
    size: {
      '...size': (name, { tokens }) => ({
        height: tokens.size[name],
        borderRadius: tokens.radius[name],
        gap: tokens.space[name].val * 0.2,
      }),
    },
  } as const,
  defaultVariants: {
    size: '$medium',
  },
})

// 3. Create text with same context (variants auto-sync)
export const ButtonText = styled(Text, {
  name: 'ButtonText',
  context: ButtonContext,
  variants: {
    size: {
      '...fontSize': (name, { font }) => ({
        fontSize: font?.size[name],
      }),
    },
  } as const,
})

// 4. Compose with withStaticProperties
export const Button = withStaticProperties(ButtonFrame, {
  Props: ButtonContext.Provider,
  Text: ButtonText,
})
```

**Usage**:
```tsx
<Button size="$large">
  <Button.Text>Click me</Button.Text>
</Button>

// Or override defaults from above:
<Button.Props size="$small">
  <Button><Button.Text>Small</Button.Text></Button>
</Button.Props>
```

**Note**: `context` pattern does not work with compiler flattening. Use for higher-level components (Button, Card), not primitives (Stack, Text).

## styleable() for Wrapper Components

When wrapping a styled component in a functional component, use `.styleable()` to preserve variant inheritance:

```tsx
const StyledText = styled(Text)

// WITHOUT styleable - BROKEN variant inheritance
const BrokenWrapper = (props) => <StyledText {...props} />

// WITH styleable - CORRECT
const CorrectWrapper = StyledText.styleable((props, ref) => (
  <StyledText ref={ref} {...props} />
))

// Now this works:
const StyledCorrectWrapper = styled(CorrectWrapper, {
  variants: {
    bold: { true: { fontWeight: 'bold' } },
  },
})
```

### Adding Extra Props

Pass generic type argument for additional props:

```tsx
type ExtraProps = { icon?: React.ReactNode }

const IconText = StyledText.styleable<ExtraProps>((props, ref) => {
  const { icon, ...rest } = props
  return (
    <XStack>
      {icon}
      <StyledText ref={ref} {...rest} />
    </XStack>
  )
})
```

## accept Prop for Custom Components

Enable token/theme resolution on non-standard props:

```tsx
// For SVG fill/stroke that should accept theme colors
const StyledSVG = styled(SVG, {}, {
  accept: { fill: 'color', stroke: 'color' } as const,
})

// Usage: <StyledSVG fill="$blue10" />

// For style objects (like ScrollView's contentContainerStyle)
const MyScrollView = styled(ScrollView, {}, {
  accept: { contentContainerStyle: 'style' } as const,
})

// Usage: <MyScrollView contentContainerStyle={{ padding: '$4' }} />
```

**Important**: Use `as const` on the accept object.

## Prop Order Matters

In `styled()`, prop order determines override priority:

```tsx
// backgroundColor can be overridden by props
const Overridable = (props) => (
  <View backgroundColor="$red10" {...props} width={200} />
)
// width CANNOT be overridden (comes after spread)

// Variant order matters too:
<Component scale={3} huge />  // scale = 3 (scale comes first)
<Component huge scale={3} />  // scale = 2 (huge overrides)
```

## Anti-Patterns

### Dynamic Styles Break Optimization

```tsx
// BAD - breaks compiler optimization
<View style={{ width: someVariable * 2 }} />
<View backgroundColor={isDark ? '$gray1' : '$gray12'} />

// GOOD - use variants
const Box = styled(View, {
  variants: {
    dark: { true: { backgroundColor: '$gray1' }, false: { backgroundColor: '$gray12' } },
  },
})
<Box dark={isDark} />
```

### Inline Functions

```tsx
// BAD - new function every render
<View onPress={() => handlePress(id)} />

// GOOD - stable reference
const handlePressCallback = useCallback(() => handlePress(id), [id])
<View onPress={handlePressCallback} />
```

### Wrong Import Paths

```tsx
// These are different packages with different contents:
import { View } from 'tamagui'           // Full UI kit
import { View } from '@tamagui/core'     // Core only (smaller)
import { Button } from '@tamagui/button' // Individual component

// Pick one approach and be consistent
```

### Mixing RN StyleSheet with Tamagui

```tsx
// BAD - StyleSheet values don't resolve tokens
const styles = StyleSheet.create({ box: { padding: 20 } })
<View style={styles.box} backgroundColor="$blue10" />

// GOOD - all Tamagui
<View padding="$4" backgroundColor="$blue10" />
```

### Platform.OS Branching for Dialog/Sheet

```tsx
// BAD - manual platform branching
if (Platform.OS === 'web') {
  return <Dialog>...</Dialog>
}
return <Sheet>...</Sheet>

// GOOD - use Adapt (see @DIALOG_PATTERNS.md)
<Dialog>
  <Dialog.Portal>...</Dialog.Portal>
  <Adapt when="sm" platform="touch">
    <Sheet><Adapt.Contents /></Sheet>
  </Adapt>
</Dialog>
```

## Fetching Current Documentation

For latest API details, fetch markdown docs directly:

```bash
# Core docs
curl -sL "https://tamagui.dev/docs/core/configuration.md"
curl -sL "https://tamagui.dev/docs/core/styled.md"
curl -sL "https://tamagui.dev/docs/core/variants.md"
curl -sL "https://tamagui.dev/docs/core/animations.md"

# Component docs
curl -sL "https://tamagui.dev/ui/sheet.md"
curl -sL "https://tamagui.dev/ui/dialog.md"
curl -sL "https://tamagui.dev/ui/select.md"

# Full docs index
curl -sL "https://tamagui.dev/llms.txt"
```

For HTML pages, use the web-fetch skill with appropriate selectors.

## Quick Reference

### Config v4 Shorthands (Tailwind-aligned)

| Shorthand | Property |
|-----------|----------|
| `bg` | backgroundColor |
| `p` | padding |
| `m` | margin |
| `w` | width |
| `h` | height |
| `br` | borderRadius |

### Media Query Breakpoints

| Token | Default | Server Default |
|-------|---------|----------------|
| `$xs` | 660px | true |
| `$sm` | 800px | false |
| `$md` | 1020px | false |
| `$lg` | 1280px | false |
| `$xl` | 1420px | false |

### Animation Drivers

| Driver | Platform | Use Case |
|--------|----------|----------|
| `css` | Web | Default, best performance |
| `react-native-reanimated` | Native | Required for native animations |

## Additional Pattern Files

- @DIALOG_PATTERNS.md - Dialog, Sheet, Adapt, accessibility
- @FORM_PATTERNS.md - Form, Input, Label, validation with zod
- @ANIMATION_PATTERNS.md - Animation drivers, enterStyle/exitStyle
- @OVERLAY_PATTERNS.md - Popover, Tooltip, Select
- @COMPILER_PATTERNS.md - Compiler optimization details
- @DESIGN_SYSTEM.md - Design tokens and theming

Quick Install

$npx ai-builder add skill 0xBigBoss/tamagui-best-practices

Details

Type
skill
Author
0xBigBoss
Slug
0xBigBoss/tamagui-best-practices
Created
4d ago