gluestack-ui logopreview
Docs
Blog
Get Updates
Prompt to React Native
IntroductionQuick Start
InstallationTooling SetupVS Code ExtensionsFigma UI KitCLIgluestack-ui-nativewind-utils
AccessibilityUniversal
Benchmarks
Default TokensCustomizing ThemeDark Mode
All Components
HeadingrscTextrsc
BoxrscCenterrscDividerHStackrscVStackrscGridalpha, rsc
AlertProgressSpinnerToast
BadgeCardrscTablealphaTabsalpha
ButtonCheckboxDateTimePickerCalendarFormControlInputLinkPressableRadioSelectSliderSwitchTextarea
AlertDialogDrawerLiquid GlassMenuModalPopoverPortalTooltipImage Viewer
ActionsheetAccordionBottomSheetalpha
AvatarImageIconrsc
FabSkeletonalpha, rsc
useBreakPointValueuseMediaQuery
Dashboard AppKitchensink AppTodo AppStarter KitAppLighter
LinearGradient
Building Ecommerce App
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