Install
$ agentstack add skill-gluestack-agent-skills-styling ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Gluestack UI v5 — Styling Patterns
This sub-skill focuses on styling patterns, theming, colors, spacing, dark mode, and variant management for gluestack-ui v5 (Tailwind v4 CSS-first).
Rule 3: Semantic Color Tokens Over Raw Values (v5)
CRITICAL: You MUST use only Gluestack v5 semantic tokens. In v5, these tokens are defined as CSS custom properties in global.css via @layer theme and mapped to Tailwind utilities via @theme inline — not in a tailwind.config.js. Generic tokens like typography-*, neutral-*, gray-*, slate-*, or any numbered color tokens (red-500, blue-600, etc.) are STRICTLY PROHIBITED.
Prohibited Token Patterns
NEVER use these token patterns:
| Prohibited Pattern | Why It's Wrong | Use Instead | | ------------------ | -------------- | ----------- | | typography-* | Generic, not semantic | text-foreground, text-muted-foreground, text-card-foreground | | neutral-* | Generic, not semantic | text-foreground, bg-background, bg-muted | | gray-*, slate-* | Raw color, not semantic | text-muted-foreground, bg-muted, border-border | | text-red-500, bg-red-600 | Numbered colors, not semantic | text-destructive, bg-destructive | | text-green-500, bg-green-600 | Numbered colors, not semantic | text-primary (for success states) | | text-blue-500, bg-blue-600 | Numbered colors, not semantic | text-primary, bg-primary | | border-gray-200 | Raw color, not semantic | border-border | | #DC2626, #3b82f6 (inline) | Hex values, not semantic | text-destructive, bg-primary | | bg-white, bg-black | Raw colors, not semantic | bg-background, text-foreground | | text-opacity-* | Opacity utilities | Use alpha values: text-foreground/70 |
Correct Semantic Token Replacement Guide
Use Gluestack v5 semantic tokens instead of raw Tailwind colors or arbitrary values:
| Instead of | Use | | ---------- | --- | | text-red-500 | text-destructive | | text-green-500 | text-primary (for success) | | text-blue-500 | text-primary | | text-gray-500, text-neutral-500 | text-muted-foreground | | text-gray-900, text-typography-900 | text-foreground | | bg-blue-600 | bg-primary | | bg-gray-100, bg-neutral-100 | bg-muted | | bg-gray-50 | bg-background | | border-gray-200, border-neutral-200 | border-border | | #DC2626 (inline) | text-destructive | | bg-white | bg-background | | text-black | text-foreground |
Available Semantic Token Categories (v5)
| Token | Purpose | Usage Example | | -------------------- | ---------------------------------------- | ------------------------------------ | | primary | Brand identity, key interactive elements | bg-primary, text-primary | | primary-foreground | Text on primary backgrounds | text-primary-foreground | | secondary | Secondary actions, supporting elements | bg-secondary | | secondary-foreground | Text on secondary backgrounds | text-secondary-foreground | | background | Main background color | bg-background | | foreground | Main text color | text-foreground | | card | Card backgrounds | bg-card | | card-foreground | Text on card backgrounds | text-card-foreground | | popover | Popover/modal backgrounds | bg-popover | | popover-foreground | Text on popover backgrounds | text-popover-foreground | | muted | Muted backgrounds | bg-muted | | muted-foreground | Muted text color | text-muted-foreground | | destructive | Error states, destructive actions | bg-destructive, text-destructive | | border | Border colors | border-border | | input | Input border colors | border-input | | ring | Focus ring colors | ring-ring | | accent | Accent highlights | bg-accent | | accent-foreground | Text on accent backgrounds | text-accent-foreground |
CRITICAL: Why Semantic Tokens Are Mandatory
Semantic tokens are NOT optional. They are required for:
- Theme Consistency - Tokens automatically adapt to light/dark modes
- Maintainability - Change theme once, update everywhere
- Intent Expression -
text-destructivecommunicates purpose,text-red-500doesn't - Future-Proofing - Theme changes don't require code updates
- Accessibility - Tokens ensure proper contrast ratios
If you use generic tokens (typography-*, neutral-*) or numbered colors (gray-500, blue-600), the component will:
- Break in dark mode
- Fail to match the design system
- Create maintenance debt
- Violate gluestack-ui v5 design principles
Alpha Values
All color tokens support alpha values using the / syntax:
// ✅ CORRECT: Using alpha values with semantic tokens
// ❌ INCORRECT: Never use opacity utilities
// ✅ CORRECT: Alpha values, not opacity utilities
Correct Pattern
Error message
Success!
Primary action
Incorrect Pattern
// ❌ PROHIBITED: Numbered color tokens
Error message
// ❌ PROHIBITED: Inline hex values
Success!
// ❌ PROHIBITED: Arbitrary color values
Primary action
// ❌ PROHIBITED: Generic tokens (typography, neutral)
Heading
Description
// ❌ PROHIBITED: Gray/Slate color scales
Content
Text
// ❌ PROHIBITED: Opacity utilities instead of alpha
Muted text
Content
Rule 3: No Inline Styles
Avoid inline style props when className can achieve the same result.
Resolution Hierarchy (in order of preference)
- Component props - Use built-in props (size, variant, space)
- className utilities - Use existing Tailwind/NativeWind classes
- Gluestack component variants - Use built-in component variants
- CSS variables (
@theme inline) - Tailwind v4 auto-resolves@theme inlinetokens into utility classes (bg-primary,text-foreground, etc.) - tva (Tailwind Variant Authority) - Create reusable variant patterns
- NativeWind interop - Enable className on third-party components
- Inline styles - Only as absolute last resort with documented justification
Correct Pattern
Click Me
Incorrect Pattern
Acceptable Exceptions
Inline styles are acceptable for:
- Dynamic values - Values computed at runtime (e.g., animation values, safe area insets)
- Third-party component requirements - Components that don't support className
- Platform-specific overrides - When Platform.select is needed
// Acceptable: dynamic value from hook
// Acceptable: animation value
// Acceptable: platform-specific
Rule 4: Spacing Scale Adherence
Use only values from the standard spacing scale. Arbitrary values create maintenance burden.
Allowed Spacing Values
| Class | Size | | ----- | ----- | | 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
Correct Pattern
Incorrect Pattern
Rule 5: Dark Mode in v5 (NativeWind v5 + UniWind)
In v5, Tailwind v4 uses CSS-first configuration with @layer theme custom properties in global.css. The dark: prefix still works identically for all className usage. However, the underlying implementation differs by engine:
- NativeWind v5: Uses
@media (prefers-color-scheme: dark)inglobal.cssfor system-level theming, plus explicit.dark/.lightclass selectors for web overrides. Theme switching viaAppearance.setColorScheme(). - UniWind: Uses
:where(.dark, .dark *)and:where(.light, .light *)selectors for per-theme CSS variables. Theme switching viaUniwind.setTheme().
Both engines use the SAME semantic token names (--primary, --foreground, etc.) mapped through @theme inline — so your className never changes regardless of engine.
Correct Pattern
Component-Level Dark Mode
const CardView = ({ isDark }: { readonly isDark: boolean }) => (
Content
);
Using Data Attributes for States
Gluestack components use data attributes for interactive states. These are automatically applied by the components based on user interaction:
| State Prop | Data Attribute | Usage in className | | -------------- | -------------------- | ---------------------------------------- | | hover | data-hover | data-[hover=true]:bg-primary/90 | | active | data-active | data-[active=true]:bg-primary/80 | | disabled | data-disabled | data-[disabled=true]:opacity-50 | | focusVisible | data-focus-visible | data-[focus-visible=true]:ring-2 | | focus | data-focus | data-[focus=true]:border-ring | | invalid | data-invalid | data-[invalid=true]:border-destructive | | checked | data-checked | data-[checked=true]:bg-primary |
// Correct: Using data attributes for states in tva
const buttonStyle = tva({
base: 'rounded-md',
variants: {
variant: {
default: 'bg-primary data-[hover=true]:bg-primary/90 data-[active=true]:bg-primary/80',
destructive: 'bg-destructive data-[hover=true]:bg-destructive/90',
},
},
});
// Correct: Data attributes work automatically with component props
Submit
Rule 7: Variant-Based Styling with tva
For components with multiple style variants, use tva (Tailwind Variant Authority).
Correct Pattern
import { tva } from "@gluestack-ui/utils/nativewind-utils";
const cardStyles = tva({
base: "rounded-lg p-4",
variants: {
variant: {
default: "bg-card border border-border shadow-sm",
elevated: "bg-card shadow-hard-2",
outlined: "bg-transparent border border-border",
filled: "bg-muted",
},
size: {
sm: "p-2",
md: "p-4",
lg: "p-6",
},
},
defaultVariants: {
variant: "default",
size: "md",
},
});
const Card = ({ variant, size, className }: CardProps) => (
);
Using Parent Variants
For sub-components that inherit parent styles:
const buttonTextStyle = tva({
base: "font-sans",
parentVariants: {
variant: {
default: "text-primary-foreground",
destructive: "text-white",
outline: "text-foreground",
},
size: {
sm: "text-xs",
md: "text-sm",
lg: "text-base",
},
},
});
Rule 8: className Merging for Custom Components
Allow className override in custom components using the class parameter in tva.
Correct Pattern
interface BoxCardProps {
readonly className?: string;
readonly children: React.ReactNode;
}
const BoxCard = ({ className, children }: BoxCardProps) => {
const cardStyles = tva({
base: "rounded-lg bg-card p-4",
});
return {children};
};
Using withStyleContext for Parent-Child Communication
For components that need to share context with children:
import {
withStyleContext,
useStyleContext,
} from "@gluestack-ui/utils/nativewind-utils";
const SCOPE = "CUSTOM_COMPONENT";
const Root = withStyleContext(View, SCOPE);
const Parent = ({ variant, children }) => (
{children}
);
const Child = () => {
const { variant } = useStyleContext(SCOPE);
return ;
};
Layout Components Pattern
// ✅ CORRECT: Using space prop instead of gap className
Title
Action
Content
Anti-Patterns to Avoid
❌ Don't: Use Generic or Non-Semantic Tokens
STRICTLY PROHIBITED - These token patterns are never allowed:
// ❌ PROHIBITED: Generic typography tokens
Heading
Body
Muted
// ✅ CORRECT: Semantic tokens
Heading
Body
Muted
// ❌ PROHIBITED: Neutral color tokens
// ✅ CORRECT: Semantic tokens
// ❌ PROHIBITED: Gray/Slate color scales
// ✅ CORRECT: Semantic tokens
// ❌ PROHIBITED: Numbered color tokens
// ✅ CORRECT: Semantic tokens
❌ Don't: Use Raw Color Values
// ❌ PROHIBITED: Arbitrary hex values
// ✅ CORRECT: Semantic tokens
// ❌ PROHIBITED: Named colors
// ✅ CORRECT: Semantic tokens
❌ Don't: Use Inline Styles When className Works
// ❌ Incorrect
// ✅ Correct
❌ Don't: Use Arbitrary Spacing Values
// ❌ Incorrect
// ✅ Correct
Common Styling Patterns
Card with Semantic Tokens
Title
Description
Button Variants with tva
const buttonStyles = tva({
base: "rounded-md px-4 py-2",
variants: {
variant: {
default: "bg-primary text-primary-foreground",
destructive: "bg-destructive text-white",
outline: "border border-border bg-transparent text-foreground",
ghost: "bg-transparent text-foreground",
},
},
});
Click Me
Dark Mode Support
Adaptive content
Muted text
Token Usage Validation
How to Validate Token Usage
Before committing any code, verify that you're using ONLY semantic tokens:
✅ ALLOWED Token Patterns:
text-foreground,text-muted-foreground,text-card-foregroundtext-primary,text-primary-foregroundtext-secondary,text-secondary-foregroundtext-destructive,text-accent,text-accent-foregroundbg-background,bg-card,bg-muted,bg-popoverbg-primary,bg-secondary,bg-destructive,bg-accentborder-border,border-input,ring-ring- Alpha values:
text-foreground/70,bg-primary/90,border-border/50
❌ PROHIBITED Token Patterns:
- ❌
typography-*(typography-900, typography-700, etc.) - ❌
neutral-*(neutral-100, neutral-600, etc.) - ❌
gray-*(gray-50, gray-900, etc.) - ❌
slate-*(slate-700, slate-200, etc.) - ❌ Numbered colors:
red-500,blue-600,green-400 - ❌ Arbitrary values:
[#3b82f6],[#DC2626] - ❌ Named colors:
'red','white','black' - ❌ Opacity utilities:
opacity-70,bg-opacity-90
Token Validation Checklist
Before submitting code, verify:
- [ ] No
typography-*tokens - Replace withtext-foregroundortext-muted-foreground - [ ] No
neutral-*tokens - Replace with semantic equivalents - [ ] No
gray-*orslate-*tokens - Replace with semantic equivalents - [ ] No numbered color tokens - Replace with semantic tokens
- [ ] No arbitrary color values - Replace with semantic tokens
- [ ] No inline style colors - Use className with semantic tokens
- [ ] No opacity utilities - Use alpha values instead (
/70,/90) - [ ] All colors are semantic - Every color token expresses intent
- [ ] Dark mode compatible - Semantic tokens work in both theme
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: gluestack
- Source: gluestack/agent-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.