AgentStack
SKILL verified MIT Self-run

Gluestack Ui V5:styling

skill-gluestack-agent-skills-styling · by gluestack

Styling patterns for gluestack-ui v5 - covers semantic tokens, spacing, dark mode (NativeWind v5 + UniWind), variants with tva, CSS variables, and className merging.

No reviews yet
0 installs
2 views
0.0% view→install

Install

$ agentstack add skill-gluestack-agent-skills-styling

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No 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.

Are you the author of Gluestack Ui V5:styling? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

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:

  1. Theme Consistency - Tokens automatically adapt to light/dark modes
  2. Maintainability - Change theme once, update everywhere
  3. Intent Expression - text-destructive communicates purpose, text-red-500 doesn't
  4. Future-Proofing - Theme changes don't require code updates
  5. 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)

  1. Component props - Use built-in props (size, variant, space)
  2. className utilities - Use existing Tailwind/NativeWind classes
  3. Gluestack component variants - Use built-in component variants
  4. CSS variables (@theme inline) - Tailwind v4 auto-resolves @theme inline tokens into utility classes (bg-primary, text-foreground, etc.)
  5. tva (Tailwind Variant Authority) - Create reusable variant patterns
  6. NativeWind interop - Enable className on third-party components
  7. Inline styles - Only as absolute last resort with documented justification

Correct Pattern


  Click Me

Incorrect Pattern

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
// 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) in global.css for system-level theming, plus explicit .dark/.light class selectors for web overrides. Theme switching via Appearance.setColorScheme().
  • UniWind: Uses :where(.dark, .dark *) and :where(.light, .light *) selectors for per-theme CSS variables. Theme switching via Uniwind.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-foreground
  • text-primary, text-primary-foreground
  • text-secondary, text-secondary-foreground
  • text-destructive, text-accent, text-accent-foreground
  • bg-background, bg-card, bg-muted, bg-popover
  • bg-primary, bg-secondary, bg-destructive, bg-accent
  • border-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 with text-foreground or text-muted-foreground
  • [ ] No neutral-* tokens - Replace with semantic equivalents
  • [ ] No gray-* or slate-* 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.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.