gluestack-nativewind

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Gluestack NativeWind Design Patterns

Gluestack NativeWind 设计模式

This skill enforces constrained, opinionated styling patterns that reduce decision fatigue, improve performance, enable consistent theming, and limit the solution space to canonical patterns.
本技能强制执行受限的、约定式的样式模式,以减少决策疲劳、提升性能、实现一致的主题化,并将解决方案范围限定为标准模式。

Core Principles

核心原则

  1. Gluestack components over React Native primitives - Gluestack wraps RN with theming, accessibility, and cross-platform consistency
  2. Semantic tokens over arbitrary values - Tokens encode intent, not just appearance
  3. className over inline styles - Inline styles bypass optimization and consistency
  4. Spacing scale over pixel values - Arbitrary values create unsustainable exceptions
  5. Remove dead code - Unused patterns mislead AI and increase cognitive load
  1. 优先使用Gluestack组件而非React Native原生组件 - Gluestack为RN组件封装了主题化、无障碍支持和跨平台一致性特性
  2. 优先使用语义化令牌而非任意值 - 令牌编码的是设计意图,而非单纯的外观
  3. 优先使用className而非内联样式 - 内联样式会绕过优化机制,破坏一致性
  4. 优先使用间距刻度而非像素值 - 任意值会导致难以维护的例外情况
  5. 移除无用代码 - 未使用的模式会误导AI,增加认知负担

When to Use This Skill

何时使用本技能

  • Creating new components with styling
  • Reviewing existing component styles
  • Refactoring styles to follow the design system
  • Fixing styling inconsistencies
  • Adding dark mode support
  • Theming components
  • 创建带样式的新组件
  • 评审现有组件的样式
  • 重构样式以遵循设计系统
  • 修复样式不一致问题
  • 添加深色模式支持
  • 为组件配置主题

Rule 1: Gluestack Components Over React Native Primitives

规则1:优先使用Gluestack组件而非React Native原生组件

Always use Gluestack components instead of direct React Native imports:
React NativeGluestack Equivalent
View
from "react-native"
Box
from "@/components/ui/box"
Text
from "react-native"
Text
from "@/components/ui/text"
TouchableOpacity
from "react-native"
Pressable
from "@/components/ui/pressable"
ScrollView
from "react-native"
ScrollView
from "@/components/ui/scroll-view"
Image
from "react-native"
Image
from "@/components/ui/image"
TextInput
from "react-native"
Input
,
InputField
from "@/components/ui/input"
FlatList
from "react-native"
FlashList
from "@shopify/flash-list"
始终使用Gluestack组件,而非直接导入React Native组件:
React NativeGluestack 等效组件
View
from "react-native"
Box
from "@/components/ui/box"
Text
from "react-native"
Text
from "@/components/ui/text"
TouchableOpacity
from "react-native"
Pressable
from "@/components/ui/pressable"
ScrollView
from "react-native"
ScrollView
from "@/components/ui/scroll-view"
Image
from "react-native"
Image
from "@/components/ui/image"
TextInput
from "react-native"
Input
,
InputField
from "@/components/ui/input"
FlatList
from "react-native"
FlashList
from "@shopify/flash-list"

Correct Pattern

正确示例

tsx
import { Box } from "@/components/ui/box";
import { Text } from "@/components/ui/text";
import { Pressable } from "@/components/ui/pressable";

const Component = () => (
  <Box className="p-4">
    <Text className="text-typography-900">Hello</Text>
    <Pressable onPress={handlePress}>
      <Text>Press Me</Text>
    </Pressable>
  </Box>
);
tsx
import { Box } from "@/components/ui/box";
import { Text } from "@/components/ui/text";
import { Pressable } from "@/components/ui/pressable";

const Component = () => (
  <Box className="p-4">
    <Text className="text-typography-900">Hello</Text>
    <Pressable onPress={handlePress}>
      <Text>Press Me</Text>
    </Pressable>
  </Box>
);

Incorrect Pattern

错误示例

tsx
import { View, Text, TouchableOpacity } from "react-native";

const Component = () => (
  <View style={{ padding: 16 }}>
    <Text style={{ color: "#333" }}>Hello</Text>
    <TouchableOpacity onPress={handlePress}>
      <Text>Press Me</Text>
    </TouchableOpacity>
  </View>
);
tsx
import { View, Text, TouchableOpacity } from "react-native";

const Component = () => (
  <View style={{ padding: 16 }}>
    <Text style={{ color: "#333" }}>Hello</Text>
    <TouchableOpacity onPress={handlePress}>
      <Text>Press Me</Text>
    </TouchableOpacity>
  </View>
);

Exceptions

例外情况

  • Platform-specific code where RN primitives are explicitly required
  • Deep integration with native modules
  • Performance-critical paths where wrapper overhead matters (rare, must document)
  • 明确需要使用RN原生组件的平台特定代码
  • 与原生模块深度集成的场景
  • 对性能要求极高的路径(罕见情况,必须添加文档说明)

Rule 2: Semantic Color Tokens Over Raw Values

规则2:优先使用语义化颜色令牌而非原始值

Use Gluestack semantic tokens instead of raw Tailwind colors:
Instead ofUse
text-red-500
text-error-500
text-green-500
text-success-500
text-yellow-500
text-warning-500
text-blue-500
text-info-500
text-gray-500
text-typography-500
bg-blue-600
bg-primary-600
border-gray-200
border-outline-200
#DC2626
(inline)
text-error-600
使用Gluestack语义化令牌,而非原始Tailwind颜色:
避免使用推荐使用
text-red-500
text-error-500
text-green-500
text-success-500
text-yellow-500
text-warning-500
text-blue-500
text-info-500
text-gray-500
text-typography-500
bg-blue-600
bg-primary-600
border-gray-200
border-outline-200
#DC2626
(内联)
text-error-600

Available Semantic Token Categories

可用的语义化令牌类别

TokenPurposeScale
primary-{0-950}
Brand identity, key interactive elements0-950
secondary-{0-950}
Secondary actions, supporting elements0-950
tertiary-{0-950}
Tertiary accents0-950
error-{0-950}
Validation errors, destructive actions0-950
success-{0-950}
Positive feedback, completions0-950
warning-{0-950}
Alerts, attention-required states0-950
info-{0-950}
Informational content0-950
typography-{0-950}
Text colors0-950
outline-{0-950}
Border colors0-950
background-{0-950}
Background colors0-950
令牌用途范围
primary-{0-950}
品牌标识、核心交互元素0-950
secondary-{0-950}
次要操作、辅助元素0-950
tertiary-{0-950}
三级强调色0-950
error-{0-950}
验证错误、破坏性操作0-950
success-{0-950}
正向反馈、完成状态0-950
warning-{0-950}
警告、需要关注的状态0-950
info-{0-950}
信息类内容0-950
typography-{0-950}
文本颜色0-950
outline-{0-950}
边框颜色0-950
background-{0-950}
背景颜色0-950

Special Background Tokens

特殊背景令牌

Use state-based background tokens:
  • bg-background-error
    - Error state backgrounds
  • bg-background-warning
    - Warning state backgrounds
  • bg-background-success
    - Success state backgrounds
  • bg-background-muted
    - Muted/disabled backgrounds
  • bg-background-info
    - Informational backgrounds
使用基于状态的背景令牌:
  • bg-background-error
    - 错误状态背景
  • bg-background-warning
    - 警告状态背景
  • bg-background-success
    - 成功状态背景
  • bg-background-muted
    - 弱化/禁用状态背景
  • bg-background-info
    - 信息类背景

Correct Pattern

正确示例

tsx
<Box className="bg-error-500">
  <Text className="text-typography-0">Error message</Text>
</Box>

<Box className="border border-outline-300 bg-background-50">
  <Text className="text-success-600">Success!</Text>
</Box>
tsx
<Box className="bg-error-500">
  <Text className="text-typography-0">Error message</Text>
</Box>

<Box className="border border-outline-300 bg-background-50">
  <Text className="text-success-600">Success!</Text>
</Box>

Incorrect Pattern

错误示例

tsx
<Box className="bg-red-500">
  <Text className="text-white">Error message</Text>
</Box>

<Box style={{ backgroundColor: '#DC2626' }}>
  <Text style={{ color: 'green' }}>Success!</Text>
</Box>
For complete token reference, see
references/color-tokens.md
.
tsx
<Box className="bg-red-500">
  <Text className="text-white">Error message</Text>
</Box>

<Box style={{ backgroundColor: '#DC2626' }}>
  <Text style={{ color: 'green' }}>Success!</Text>
</Box>
完整的令牌参考请查看
references/color-tokens.md

Rule 3: No Inline Styles

规则3:禁止使用内联样式

Avoid inline
style
props when className can achieve the same result.
当可以通过className实现相同效果时,避免使用内联
style
属性。

Resolution Hierarchy (in order of preference)

解决方案优先级(从高到低)

  1. className utilities - Use existing Tailwind/NativeWind classes
  2. Gluestack component variants - Use built-in component variants
  3. tva (Tailwind Variant Authority) - Create reusable variant patterns
  4. NativeWind interop - Enable className on third-party components
  5. Inline styles - Only as absolute last resort with documented justification
  1. className工具类 - 使用现有的Tailwind/NativeWind类
  2. Gluestack组件变体 - 使用内置的组件变体
  3. tva(Tailwind Variant Authority) - 创建可复用的变体模式
  4. NativeWind互操作 - 为第三方组件启用className支持
  5. 内联样式 - 仅作为最后的手段,且必须添加文档说明理由

Correct Pattern

正确示例

tsx
<Box className="w-20 h-20 rounded-full bg-background-100" />

<Text className="text-lg font-bold text-typography-900" />
tsx
<Box className="w-20 h-20 rounded-full bg-background-100" />

<Text className="text-lg font-bold text-typography-900" />

Incorrect Pattern

错误示例

tsx
<Box
  style={{
    width: 80,
    height: 80,
    borderRadius: 40,
    backgroundColor: "rgba(255, 255, 255, 0.1)",
  }}
/>
tsx
<Box
  style={{
    width: 80,
    height: 80,
    borderRadius: 40,
    backgroundColor: "rgba(255, 255, 255, 0.1)",
  }}
/>

Acceptable Exceptions

可接受的例外情况

Inline styles are acceptable for:
  1. Dynamic values - Values computed at runtime (e.g., animation values, safe area insets)
  2. Third-party component requirements - Components that don't support className
  3. Platform-specific overrides - When Platform.select is needed
tsx
// Acceptable: dynamic value from hook
<Box style={{ paddingBottom: bottomInset }} />

// Acceptable: animation value
<Animated.View style={{ transform: [{ translateX: animatedValue }] }} />
内联样式可用于以下场景:
  1. 动态值 - 运行时计算的值(如动画值、安全区域内边距)
  2. 第三方组件要求 - 不支持className的第三方组件
  3. 平台特定覆盖 - 需要使用Platform.select的场景
tsx
// 可接受:来自hook的动态值
<Box style={{ paddingBottom: bottomInset }} />

// 可接受:动画值
<Animated.View style={{ transform: [{ translateX: animatedValue }] }} />

Rule 4: Spacing Scale Adherence

规则4:遵循间距刻度

Use only values from the standard spacing scale. Arbitrary values create maintenance burden.
仅使用标准间距刻度中的值。任意值会增加维护负担。

Allowed Spacing Values

允许的间距值

ClassSize
0
0px
0.5
2px
1
4px
1.5
6px
2
8px
2.5
10px
3
12px
3.5
14px
4
16px
5
20px
6
24px
7
28px
8
32px
9
36px
10
40px
11
44px
12
48px
14
56px
16
64px
20
80px
24
96px
28
112px
32
128px
36
144px
40
160px
44
176px
48
192px
52
208px
56
224px
60
240px
64
256px
72
288px
80
320px
96
384px
类名像素值
0
0px
0.5
2px
1
4px
1.5
6px
2
8px
2.5
10px
3
12px
3.5
14px
4
16px
5
20px
6
24px
7
28px
8
32px
9
36px
10
40px
11
44px
12
48px
14
56px
16
64px
20
80px
24
96px
28
112px
32
128px
36
144px
40
160px
44
176px
48
192px
52
208px
56
224px
60
240px
64
256px
72
288px
80
320px
96
384px

Prohibited Patterns

禁止的模式

  • Arbitrary values:
    p-[13px]
    ,
    m-[27px]
    ,
    gap-[15px]
  • Non-scale decimals:
    p-2.7
    ,
    m-4.3
  • 任意值:
    p-[13px]
    ,
    m-[27px]
    ,
    gap-[15px]
  • 非刻度内的小数:
    p-2.7
    ,
    m-4.3

Correct Pattern

正确示例

tsx
<Box className="p-4 m-2 gap-3" />
<Box className="px-6 py-4 mt-8" />
tsx
<Box className="p-4 m-2 gap-3" />
<Box className="px-6 py-4 mt-8" />

Incorrect Pattern

错误示例

tsx
<Box className="p-[13px] m-[27px]" />
<Box style={{ padding: 13, margin: 27 }} />
For complete spacing reference, see
references/spacing-scale.md
.
tsx
<Box className="p-[13px] m-[27px]" />
<Box style={{ padding: 13, margin: 27 }} />
完整的间距参考请查看
references/spacing-scale.md

Rule 5: Dark Mode Using CSS Variables

规则5:使用CSS变量实现深色模式

Use the CSS variables approach with
dark:
prefix for dark mode support.
使用带
dark:
前缀的CSS变量方式来支持深色模式。

Correct Pattern

正确示例

tsx
<Box className="bg-background-0 dark:bg-background-950" />
<Text className="text-typography-900 dark:text-typography-0" />
tsx
<Box className="bg-background-0 dark:bg-background-950" />
<Text className="text-typography-900 dark:text-typography-0" />

Component-Level Dark Mode

组件级深色模式

tsx
const CardView = ({ isDark }: { readonly isDark: boolean }) => (
  <Box className={isDark ? "bg-background-950" : "bg-background-0"}>
    <Text className={isDark ? "text-typography-0" : "text-typography-900"}>
      Content
    </Text>
  </Box>
);
tsx
const CardView = ({ isDark }: { readonly isDark: boolean }) => (
  <Box className={isDark ? "bg-background-950" : "bg-background-0"}>
    <Text className={isDark ? "text-typography-0" : "text-typography-900"}>
      Content
    </Text>
  </Box>
);

Rule 6: Gluestack Sub-Component Pattern

规则6:Gluestack子组件模式

Use Gluestack's composable sub-component pattern for complex components.
对于复杂组件,使用Gluestack的可组合子组件模式。

Correct Pattern

正确示例

tsx
<Button action="primary" size="md">
  <ButtonText>Click Me</ButtonText>
  <ButtonIcon as={ChevronRightIcon} />
</Button>

<Input variant="outline" size="md">
  <InputField placeholder="Enter text" />
  <InputSlot>
    <InputIcon as={SearchIcon} />
  </InputSlot>
</Input>

<Select>
  <SelectTrigger>
    <SelectInput placeholder="Select option" />
    <SelectIcon as={ChevronDownIcon} />
  </SelectTrigger>
  <SelectPortal>
    <SelectBackdrop />
    <SelectContent>
      <SelectItem label="Option 1" value="1" />
      <SelectItem label="Option 2" value="2" />
    </SelectContent>
  </SelectPortal>
</Select>
tsx
<Button action="primary" size="md">
  <ButtonText>Click Me</ButtonText>
  <ButtonIcon as={ChevronRightIcon} />
</Button>

<Input variant="outline" size="md">
  <InputField placeholder="Enter text" />
  <InputSlot>
    <InputIcon as={SearchIcon} />
  </InputSlot>
</Input>

<Select>
  <SelectTrigger>
    <SelectInput placeholder="Select option" />
    <SelectIcon as={ChevronDownIcon} />
  </SelectTrigger>
  <SelectPortal>
    <SelectBackdrop />
    <SelectContent>
      <SelectItem label="Option 1" value="1" />
      <SelectItem label="Option 2" value="2" />
    </SelectContent>
  </SelectPortal>
</Select>

Incorrect Pattern

错误示例

tsx
// Missing sub-components
<Button>Click Me</Button>

// Text must be wrapped in ButtonText
<Button>
  Click Me  {/* Will not render correctly */}
</Button>
tsx
// 缺少子组件
<Button>Click Me</Button>

// 文本必须包裹在ButtonText中
<Button>
  Click Me  {/* 无法正确渲染 */}
</Button>

Rule 7: Variant-Based Styling with tva

规则7:使用tva实现基于变体的样式

For components with multiple style variants, use
tva
(Tailwind Variant Authority).
对于有多组样式变体的组件,使用
tva
(Tailwind Variant Authority)。

Correct Pattern

正确示例

tsx
import { tva } from "@gluestack-ui/nativewind-utils/tva";

const cardStyles = tva({
  base: "rounded-lg p-4",
  variants: {
    variant: {
      elevated: "bg-background-0 shadow-hard-2",
      outlined: "bg-transparent border border-outline-200",
      filled: "bg-background-50",
    },
    size: {
      sm: "p-2",
      md: "p-4",
      lg: "p-6",
    },
  },
  defaultVariants: {
    variant: "elevated",
    size: "md",
  },
});

const Card = ({ variant, size, className }: CardProps) => (
  <Box className={cardStyles({ variant, size, className })} />
);
tsx
import { tva } from "@gluestack-ui/nativewind-utils/tva";

const cardStyles = tva({
  base: "rounded-lg p-4",
  variants: {
    variant: {
      elevated: "bg-background-0 shadow-hard-2",
      outlined: "bg-transparent border border-outline-200",
      filled: "bg-background-50",
    },
    size: {
      sm: "p-2",
      md: "p-4",
      lg: "p-6",
    },
  },
  defaultVariants: {
    variant: "elevated",
    size: "md",
  },
});

const Card = ({ variant, size, className }: CardProps) => (
  <Box className={cardStyles({ variant, size, className })} />
);

Rule 8: className Merging for Custom Components

规则8:自定义组件的className合并

Allow className override in custom components using string concatenation.
通过字符串拼接允许自定义组件的className覆盖。

Correct Pattern

正确示例

tsx
interface BoxCardProps {
  readonly className?: string;
  readonly children: React.ReactNode;
}

const BoxCard = ({ className, children }: BoxCardProps) => (
  <Box className={`rounded-lg bg-background-0 p-4 ${className ?? ""}`}>
    {children}
  </Box>
);
tsx
interface BoxCardProps {
  readonly className?: string;
  readonly children: React.ReactNode;
}

const BoxCard = ({ className, children }: BoxCardProps) => (
  <Box className={`rounded-lg bg-background-0 p-4 ${className ?? ""}`}>
    {children}
  </Box>
);

Validation

验证

To validate styling compliance, run:
bash
python3 .claude/skills/gluestack-nativewind/scripts/validate_styling.py [path]
The script detects:
  1. Direct React Native component imports with Gluestack equivalents
  2. Raw color values without semantic tokens
  3. Inline style objects where className could be used
  4. Arbitrary bracket notation values
  5. Non-scale spacing values
要验证样式合规性,运行以下命令:
bash
python3 .claude/skills/gluestack-nativewind/scripts/validate_styling.py [path]
该脚本会检测:
  1. 直接导入存在Gluestack等效组件的React Native组件
  2. 未使用语义化令牌的原始颜色值
  3. 可使用className实现却使用了内联样式的情况
  4. 任意括号表示法的值
  5. 非刻度内的间距值

Escalation Guidance

升级指导

When a design request cannot be satisfied with existing patterns:
  1. Push back early - Explain performance and maintenance implications
  2. Propose alternatives - Map to existing tokens or suggest new semantic tokens
  3. Add to design system - If truly needed, add token to tailwind.config.js
  4. Document exception - If inline style is unavoidable, add JSDoc explaining why
当设计需求无法通过现有模式满足时:
  1. 尽早反馈 - 说明性能和维护方面的影响
  2. 提出替代方案 - 映射到现有令牌,或建议新增语义化令牌
  3. 添加到设计系统 - 如果确实需要,将令牌添加到tailwind.config.js
  4. 记录例外情况 - 如果必须使用内联样式,添加JSDoc说明理由

Reference Documentation

参考文档

For detailed mappings and complete token lists:
  • references/component-mapping.md
    - Gluestack equivalents for React Native primitives
  • references/color-tokens.md
    - Complete semantic color token reference
  • references/spacing-scale.md
    - Allowed spacing values with pixel equivalents
如需详细的映射关系和完整的令牌列表:
  • references/component-mapping.md
    - React Native原生组件对应的Gluestack等效组件
  • references/color-tokens.md
    - 完整的语义化颜色令牌参考
  • references/spacing-scale.md
    - 允许的间距值及对应的像素等效值