gluestack-ui logopreview
Docs
Blog
Get Updates
Prompt to React Native
Home
Components
Hooks
Apps
MCP Server
Guides
Home
Overview
IntroductionQuick Start
Getting Started
InstallationTooling SetupVS Code ExtensionsFigma UI KitCLIgluestack-ui-nativewind-utils
Core Concepts
AccessibilityUniversal
Performance
Benchmarks
Theme Configuration
Default TokensCustomizing ThemeDark Mode
Components
All Components
Typography
HeadingrscTextrsc
Layout
BoxrscCenterrscDividerHStackrscVStackrscGridalpha, rsc
Feedback
AlertProgressSpinnerToast
Data Display
BadgeCardrscTablealpha
Forms
ButtonCheckboxFormControlInputLinkPressableRadioSelectSliderSwitchTextarea
Overlay
AlertDialogDrawerMenuModalPopoverPortalTooltip
Disclosure
ActionsheetAccordionBottomSheetalpha
Media And Icons
AvatarImageIconrsc
Others
FabSkeletonalpha, rsc
Hooks
useBreakPointValue
useMediaQuery
Apps
Dashboard App
Kitchensink App
Todo App
Starter Kit
AppLighter
MCP Server
MCP Server
Guides
Recipes
LinearGradient
Tutorials
Building Ecommerce App
More
Upgrade to v2Upgrade to v3Upgrade to v4FAQsReleasesChangelogRoadmapTroubleshootingDiscord FAQs

Customizing Theme

Customize your UI theme in gluestack-ui v4 using shadcn-inspired semantic color tokens. Define your theme in config.ts and apply it via GluestackUIProvider for consistent, accessible styling.

Customizing Tokens

gluestack-ui v4 uses a semantic color token system inspired by shadcn/ui. The tokens are defined separately for light and dark modes, and they automatically adapt when the mode changes. The color system uses semantic names (like
primary
,
secondary
,
background
) rather than numerical scales (50-900), making your theme more maintainable and meaningful.

Understanding the Token Structure

Color tokens are defined in RGB format without the
rgb()
wrapper
, which allows Tailwind to apply opacity modifiers:
// Instead of: 'rgb(23, 23, 23)'
// Use: '23 23 23'
This enables opacity syntax like
bg-primary/50
for 50% opacity.

Customizing Colors

To customize tokens, follow these steps:

Step 1: Update color values in
gluestack-ui-provider/config.ts

import { vars } from 'nativewind';

export const config = {
  light: vars({
    // Base colors
    '--background': '255 255 255',     // White background
    '--foreground': '10 10 10',        // Almost black text

    // Primary brand color
    '--primary': '59 130 246',         // Blue-500
    '--primary-foreground': '255 255 255', // White text on primary

    // Secondary color
    '--secondary': '245 245 245',      // Gray-100
    '--secondary-foreground': '23 23 23', // Dark text on secondary

    // Accent color
    '--accent': '251 146 60',          // Orange-400
    '--accent-foreground': '255 255 255', // White text on accent

    // Muted elements
    '--muted': '245 245 245',          // Gray-100
    '--muted-foreground': '115 115 115', // Gray-500

    // Destructive/error color
    '--destructive': '239 68 68',      // Red-500

    // Component backgrounds
    '--card': '255 255 255',           // White cards
    '--popover': '255 255 255',        // White popovers
    '--popover-foreground': '10 10 10', // Dark text in popovers

    // Borders and inputs
    '--border': '229 229 229',         // Gray-200
    '--input': '229 229 229',          // Gray-200
    '--ring': '59 130 246',            // Blue-500 focus ring
  }),

  dark: vars({
    // Base colors
    '--background': '10 10 10',        // Almost black background
    '--foreground': '250 250 250',     // Almost white text

    // Primary brand color (inverted for dark mode)
    '--primary': '147 197 253',        // Blue-300
    '--primary-foreground': '23 23 23', // Dark text on primary

    // Secondary color
    '--secondary': '38 38 38',         // Gray-800
    '--secondary-foreground': '250 250 250', // Light text on secondary

    // Accent color
    '--accent': '251 146 60',          // Orange-400
    '--accent-foreground': '255 255 255', // White text on accent

    // Muted elements
    '--muted': '38 38 38',             // Gray-800
    '--muted-foreground': '161 161 161', // Gray-400

    // Destructive/error color
    '--destructive': '252 165 165',    // Red-300

    // Component backgrounds
    '--card': '23 23 23',              // Dark cards
    '--popover': '23 23 23',           // Dark popovers
    '--popover-foreground': '250 250 250', // Light text in popovers

    // Borders and inputs
    '--border': '46 46 46',            // Gray-700
    '--input': '46 46 46',             // Gray-700
    '--ring': '147 197 253',           // Blue-300 focus ring
  }),
};

Step 2: Map tokens to Tailwind in
tailwind.config.js

Ensure your Tailwind config maps the CSS variables to Tailwind classes:
module.exports = {
  theme: {
    extend: {
      colors: {
        border: 'rgb(var(--border))',
        input: 'rgb(var(--input))',
        ring: 'rgb(var(--ring))',
        background: 'rgb(var(--background))',
        foreground: 'rgb(var(--foreground))',
        primary: {
          DEFAULT: 'rgb(var(--primary))',
          foreground: 'rgb(var(--primary-foreground))',
        },
        secondary: {
          DEFAULT: 'rgb(var(--secondary))',
          foreground: 'rgb(var(--secondary-foreground))',
        },
        destructive: {
          DEFAULT: 'rgb(var(--destructive))',
        },
        muted: {
          DEFAULT: 'rgb(var(--muted))',
          foreground: 'rgb(var(--muted-foreground))',
        },
        accent: {
          DEFAULT: 'rgb(var(--accent))',
          foreground: 'rgb(var(--accent-foreground))',
        },
        popover: {
          DEFAULT: 'rgb(var(--popover))',
          foreground: 'rgb(var(--popover-foreground))',
        },
        card: {
          DEFAULT: 'rgb(var(--card))',
        },
      },
    },
  },
};

Usage in Components

Once configured, use the semantic tokens in your components:
// Primary button
<Button className="bg-primary text-primary-foreground">
  <ButtonText>Primary Action</ButtonText>
</Button>

// Secondary button
<Button className="bg-secondary text-secondary-foreground">
  <ButtonText>Secondary Action</ButtonText>
</Button>

// Card with proper contrast
<Box className="bg-card border border-border p-4">
  <Text className="text-foreground">Card content</Text>
  <Text className="text-muted-foreground">Muted description</Text>
</Box>

// Destructive action
<Button className="bg-destructive text-primary-foreground">
  <ButtonText>Delete</ButtonText>
</Button>

// With opacity
<Box className="bg-primary/10">
  <Text className="text-primary">Subtle primary background</Text>
</Box>

Adding Custom Tokens

You can add your own custom tokens following the same pattern:

Step 1: Add to config.ts

export const config = {
  light: vars({
    // ... existing tokens
    '--success': '34 197 94',          // Green-500
    '--success-foreground': '255 255 255',
    '--warning': '251 146 60',         // Orange-400
    '--warning-foreground': '255 255 255',
  }),
  dark: vars({
    // ... existing tokens
    '--success': '134 239 172',        // Green-300
    '--success-foreground': '23 23 23',
    '--warning': '253 186 116',        // Orange-300
    '--warning-foreground': '23 23 23',
  }),
};

Step 2: Add to tailwind.config.js

colors: {
  // ... existing colors
  success: {
    DEFAULT: 'rgb(var(--success))',
    foreground: 'rgb(var(--success-foreground))',
  },
  warning: {
    DEFAULT: 'rgb(var(--warning))',
    foreground: 'rgb(var(--warning-foreground))',
  },
}

Adding Custom Font Sizes

You can also add custom typography tokens:

Step 1: Add to config.ts

export const config = {
  light: vars({
    // ... existing tokens
    '--font-size-custom': '80',        // 80px
  }),
  dark: vars({
    // ... existing tokens
    '--font-size-custom': '80',
  }),
};

Step 2: Add to tailwind.config.js

fontSize: {
  'custom-heading-xl': 'var(--font-size-custom)',
}

Step 3: Configure tva for the component

For custom font sizes to work with
tva
(Tailwind Variants Authority), add configuration:
import { tva } from '@gluestack-ui/utils/nativewind-utils';

const config = {
  twMerge: true,
  twMergeConfig: {
    classGroups: {
      'font-size': [
        {
          text: ['custom-heading-xl'],
        },
      ],
    },
  },
};

export const textStyle = tva({
  base: 'text-foreground',
  variants: {
    size: {
      'custom-heading-xl': 'text-custom-heading-xl',
    },
  },
}, config);
Alternatively, set a
global tailwind-variants config
to affect all components.

Best Practices

  1. Step 1:Use semantic names - Name tokens by purpose (
    primary
    ,
    secondary
    ) not appearance (
    blue
    ,
    gray
    )
  2. Step 2:Maintain contrast - Always provide foreground tokens for colored backgrounds
  3. Step 3:Test both modes - Verify your colors work in both light and dark mode
  4. Step 4:Use opacity sparingly - The
    /50
    syntax is great for subtle backgrounds
  5. Step 5:Follow the pattern - Keep the RGB format without
    rgb()
    wrapper for Tailwind compatibility
For a complete list of default tokens, see
Default Tokens
.
For extending Tailwind config (fonts, breakpoints, border radius, etc.), refer to the
Tailwind CSS documentation
.
Edit this page on GitHub
Go backDefault Tokens
Up nextDark Mode
Go backDefault Tokens
Up nextDark Mode