Important Note
This is the documentation for gluestack-ui v2 (beta). For @gluestack-ui/themed (stable) documentation, refer to gluestack-ui v1.
Installation
To get started with gluestack-ui v2, check out this quick installation guide. It provides simple steps to help you install and use the library in your projects.
CLI
Manual
Step 1: Setup your project
If you are starting with a new project, setup your project with Next.js or Expo. If you already have a project, you can skip this step.
Prerequisites
Ensure you have the following prerequisites installed on your project to use gluestack-ui CLI:
- Node.js: Version 16 or higher.
- React: Version 18 or higher.
Step 2: Initialize
Go to your project, and use the init command at the root of your project to add GluestackUIProvider and the gluestack-ui-provider/config.ts file to your project..
npx gluestack-ui init
Important Note
Installation using gluestack-ui CLI in Expo projects supports for Expo SDK 50 and above only. For Expo SDK < 49, please refer to the manual installation.
Your project is now ready to use gluestack-ui components. To add gluestack-ui components to your project using the CLI, refer to the above command or use the CLI guide.
npx gluestack-ui add box
If you encounter issues during the CLI installation, refer to the manual installation guide available.
Step 1: Setup your project.
Setup nativewind in your project following NativeWind documentation.
Step 2: Install dependencies
Install the dependencies of gluestack-ui in your project. This can be done using the following command:
yarn add @gluestack-ui/nativewind-utils
OR
npm i @gluestack-ui/nativewind-utils
Step 2.1: Update Tailwind configuration
Update tailwind.config.js file with the following code
const gluestackPlugin = require('@gluestack-ui/nativewind-utils/tailwind-plugin');/** @type {import('tailwindcss').Config} */module.exports = {darkMode: process.env.DARK_MODE ? process.env.DARK_MODE : 'media',content: ['./src/**/*.{html,js,jsx,ts,tsx}','./src/core-components/**/**/*.{html,js,jsx,ts,tsx}','./src/components/**/*.{html,js,jsx,ts,tsx,mdx}','./src/hooks/**/*.{html,js,jsx,ts,tsx,mdx}',],presets: [require('nativewind/preset')],safelist: [{pattern:/(bg|border|text|stroke|fill)-(primary|secondary|tertiary|error|success|warning|info|typography|outline|background)-(0|50|100|200|300|400|500|600|700|800|900|950|white|gray|black|error|warning|muted|success|info|light|dark)/,},],theme: {extend: {colors: {primary: {0: 'rgb(var(--color-primary-0)/<alpha-value>)',50: 'rgb(var(--color-primary-50)/<alpha-value>)',100: 'rgb(var(--color-primary-100)/<alpha-value>)',200: 'rgb(var(--color-primary-200)/<alpha-value>)',300: 'rgb(var(--color-primary-300)/<alpha-value>)',400: 'rgb(var(--color-primary-400)/<alpha-value>)',500: 'rgb(var(--color-primary-500)/<alpha-value>)',600: 'rgb(var(--color-primary-600)/<alpha-value>)',700: 'rgb(var(--color-primary-700)/<alpha-value>)',800: 'rgb(var(--color-primary-800)/<alpha-value>)',900: 'rgb(var(--color-primary-900)/<alpha-value>)',950: 'rgb(var(--color-primary-950)/<alpha-value>)',},secondary: {0: 'rgb(var(--color-secondary-0)/<alpha-value>)',50: 'rgb(var(--color-secondary-50)/<alpha-value>)',100: 'rgb(var(--color-secondary-100)/<alpha-value>)',200: 'rgb(var(--color-secondary-200)/<alpha-value>)',300: 'rgb(var(--color-secondary-300)/<alpha-value>)',400: 'rgb(var(--color-secondary-400)/<alpha-value>)',500: 'rgb(var(--color-secondary-500)/<alpha-value>)',600: 'rgb(var(--color-secondary-600)/<alpha-value>)',700: 'rgb(var(--color-secondary-700)/<alpha-value>)',800: 'rgb(var(--color-secondary-800)/<alpha-value>)',900: 'rgb(var(--color-secondary-900)/<alpha-value>)',950: 'rgb(var(--color-secondary-950)/<alpha-value>)',},tertiary: {50: 'rgb(var(--color-tertiary-50)/<alpha-value>)',100: 'rgb(var(--color-tertiary-100)/<alpha-value>)',200: 'rgb(var(--color-tertiary-200)/<alpha-value>)',300: 'rgb(var(--color-tertiary-300)/<alpha-value>)',400: 'rgb(var(--color-tertiary-400)/<alpha-value>)',500: 'rgb(var(--color-tertiary-500)/<alpha-value>)',600: 'rgb(var(--color-tertiary-600)/<alpha-value>)',700: 'rgb(var(--color-tertiary-700)/<alpha-value>)',800: 'rgb(var(--color-tertiary-800)/<alpha-value>)',900: 'rgb(var(--color-tertiary-900)/<alpha-value>)',950: 'rgb(var(--color-tertiary-950)/<alpha-value>)',},error: {0: 'rgb(var(--color-error-0)/<alpha-value>)',50: 'rgb(var(--color-error-50)/<alpha-value>)',100: 'rgb(var(--color-error-100)/<alpha-value>)',200: 'rgb(var(--color-error-200)/<alpha-value>)',300: 'rgb(var(--color-error-300)/<alpha-value>)',400: 'rgb(var(--color-error-400)/<alpha-value>)',500: 'rgb(var(--color-error-500)/<alpha-value>)',600: 'rgb(var(--color-error-600)/<alpha-value>)',700: 'rgb(var(--color-error-700)/<alpha-value>)',800: 'rgb(var(--color-error-800)/<alpha-value>)',900: 'rgb(var(--color-error-900)/<alpha-value>)',950: 'rgb(var(--color-error-950)/<alpha-value>)',},success: {0: 'rgb(var(--color-success-0)/<alpha-value>)',50: 'rgb(var(--color-success-50)/<alpha-value>)',100: 'rgb(var(--color-success-100)/<alpha-value>)',200: 'rgb(var(--color-success-200)/<alpha-value>)',300: 'rgb(var(--color-success-300)/<alpha-value>)',400: 'rgb(var(--color-success-400)/<alpha-value>)',500: 'rgb(var(--color-success-500)/<alpha-value>)',600: 'rgb(var(--color-success-600)/<alpha-value>)',700: 'rgb(var(--color-success-700)/<alpha-value>)',800: 'rgb(var(--color-success-800)/<alpha-value>)',900: 'rgb(var(--color-success-900)/<alpha-value>)',950: 'rgb(var(--color-success-950)/<alpha-value>)',},warning: {0: 'rgb(var(--color-warning-0)/<alpha-value>)',50: 'rgb(var(--color-warning-50)/<alpha-value>)',100: 'rgb(var(--color-warning-100)/<alpha-value>)',200: 'rgb(var(--color-warning-200)/<alpha-value>)',300: 'rgb(var(--color-warning-300)/<alpha-value>)',400: 'rgb(var(--color-warning-400)/<alpha-value>)',500: 'rgb(var(--color-warning-500)/<alpha-value>)',600: 'rgb(var(--color-warning-600)/<alpha-value>)',700: 'rgb(var(--color-warning-700)/<alpha-value>)',800: 'rgb(var(--color-warning-800)/<alpha-value>)',900: 'rgb(var(--color-warning-900)/<alpha-value>)',950: 'rgb(var(--color-warning-950)/<alpha-value>)',},info: {0: 'rgb(var(--color-info-0)/<alpha-value>)',50: 'rgb(var(--color-info-50)/<alpha-value>)',100: 'rgb(var(--color-info-100)/<alpha-value>)',200: 'rgb(var(--color-info-200)/<alpha-value>)',300: 'rgb(var(--color-info-300)/<alpha-value>)',400: 'rgb(var(--color-info-400)/<alpha-value>)',500: 'rgb(var(--color-info-500)/<alpha-value>)',600: 'rgb(var(--color-info-600)/<alpha-value>)',700: 'rgb(var(--color-info-700)/<alpha-value>)',800: 'rgb(var(--color-info-800)/<alpha-value>)',900: 'rgb(var(--color-info-900)/<alpha-value>)',950: 'rgb(var(--color-info-950)/<alpha-value>)',},typography: {0: 'rgb(var(--color-typography-0)/<alpha-value>)',50: 'rgb(var(--color-typography-50)/<alpha-value>)',100: 'rgb(var(--color-typography-100)/<alpha-value>)',200: 'rgb(var(--color-typography-200)/<alpha-value>)',300: 'rgb(var(--color-typography-300)/<alpha-value>)',400: 'rgb(var(--color-typography-400)/<alpha-value>)',500: 'rgb(var(--color-typography-500)/<alpha-value>)',600: 'rgb(var(--color-typography-600)/<alpha-value>)',700: 'rgb(var(--color-typography-700)/<alpha-value>)',800: 'rgb(var(--color-typography-800)/<alpha-value>)',900: 'rgb(var(--color-typography-900)/<alpha-value>)',950: 'rgb(var(--color-typography-950)/<alpha-value>)',white: '#FFFFFF',gray: '#D4D4D4',black: '#181718',},outline: {0: 'rgb(var(--color-outline-0)/<alpha-value>)',50: 'rgb(var(--color-outline-50)/<alpha-value>)',100: 'rgb(var(--color-outline-100)/<alpha-value>)',200: 'rgb(var(--color-outline-200)/<alpha-value>)',300: 'rgb(var(--color-outline-300)/<alpha-value>)',400: 'rgb(var(--color-outline-400)/<alpha-value>)',500: 'rgb(var(--color-outline-500)/<alpha-value>)',600: 'rgb(var(--color-outline-600)/<alpha-value>)',700: 'rgb(var(--color-outline-700)/<alpha-value>)',800: 'rgb(var(--color-outline-800)/<alpha-value>)',900: 'rgb(var(--color-outline-900)/<alpha-value>)',950: 'rgb(var(--color-outline-950)/<alpha-value>)',},background: {0: 'rgb(var(--color-background-0)/<alpha-value>)',50: 'rgb(var(--color-background-50)/<alpha-value>)',100: 'rgb(var(--color-background-100)/<alpha-value>)',200: 'rgb(var(--color-background-200)/<alpha-value>)',300: 'rgb(var(--color-background-300)/<alpha-value>)',400: 'rgb(var(--color-background-400)/<alpha-value>)',500: 'rgb(var(--color-background-500)/<alpha-value>)',600: 'rgb(var(--color-background-600)/<alpha-value>)',700: 'rgb(var(--color-background-700)/<alpha-value>)',800: 'rgb(var(--color-background-800)/<alpha-value>)',900: 'rgb(var(--color-background-900)/<alpha-value>)',950: 'rgb(var(--color-background-950)/<alpha-value>)',error: 'rgb(var(--color-background-error)/<alpha-value>)',warning: 'rgb(var(--color-background-warning)/<alpha-value>)',muted: 'rgb(var(--color-background-muted)/<alpha-value>)',success: 'rgb(var(--color-background-success)/<alpha-value>)',info: 'rgb(var(--color-background-info)/<alpha-value>)',light: '#FBFBFB',dark: '#181719',},indicator: {primary: 'rgb(var(--color-indicator-primary)/<alpha-value>)',info: 'rgb(var(--color-indicator-info)/<alpha-value>)',error: 'rgb(var(--color-indicator-error)/<alpha-value>)',},},fontFamily: {heading: undefined,body: undefined,mono: undefined,roboto: ['Roboto', 'sans-serif'],},fontWeight: {extrablack: '950',},fontSize: {'2xs': '10px',},boxShadow: {'hard-1': '-2px 2px 8px 0px rgba(38, 38, 38, 0.20)','hard-2': '0px 3px 10px 0px rgba(38, 38, 38, 0.20)','hard-3': '2px 2px 8px 0px rgba(38, 38, 38, 0.20)','hard-4': '0px -3px 10px 0px rgba(38, 38, 38, 0.20)','hard-5': '0px 2px 10px 0px rgba(38, 38, 38, 0.10)','soft-1': '0px 0px 10px rgba(38, 38, 38, 0.1)','soft-2': '0px 0px 20px rgba(38, 38, 38, 0.2)','soft-3': '0px 0px 30px rgba(38, 38, 38, 0.1)','soft-4': '0px 0px 40px rgba(38, 38, 38, 0.1)',},},},plugins: [gluestackPlugin],};
Step 2.2: Configure components path
Create a components/ui folder inside src folder and add path in tsconfig.json
// ... (other configs)compilerOptions: {// ..."paths": {// ..."@/*": ["./src/*"] // Add relative path},}
Step 2.3: Configure GluestackUIProvider
To add config, create a gluestack-ui-provider/config.ts file in your components/ui folder and paste the following code.
"use client"import { vars } from "nativewind"export const config = {light: vars({"--color-primary-0": "179 179 179","--color-primary-50": "153 153 153","--color-primary-100": "128 128 128","--color-primary-200": "115 115 115","--color-primary-300": "102 102 102","--color-primary-400": "82 82 82","--color-primary-500": "51 51 51","--color-primary-600": "41 41 41","--color-primary-700": "31 31 31","--color-primary-800": "13 13 13","--color-primary-900": "10 10 10","--color-primary-950": "8 8 8",/* Secondary */"--color-secondary-0": "254 255 255","--color-secondary-50": "241 242 242","--color-secondary-100": "231 232 232","--color-secondary-200": "219 219 219","--color-secondary-300": "175 176 176","--color-secondary-400": "114 115 115","--color-secondary-500": "94 95 95","--color-secondary-600": "81 82 82","--color-secondary-700": "63 64 64","--color-secondary-800": "39 38 38","--color-secondary-900": "24 23 23","--color-secondary-950": "11 12 12",/* Tertiary */"--color-tertiary-0": "255 250 245","--color-tertiary-50": "255 242 229","--color-tertiary-100": "255 233 213","--color-tertiary-200": "254 209 170","--color-tertiary-300": "253 180 116","--color-tertiary-400": "251 157 75","--color-tertiary-500": "231 129 40","--color-tertiary-600": "215 117 31","--color-tertiary-700": "180 98 26","--color-tertiary-800": "130 73 23","--color-tertiary-900": "108 61 19","--color-tertiary-950": "84 49 18",/* Error */"--color-error-0": "254 233 233","--color-error-50": "254 226 226","--color-error-100": "254 202 202","--color-error-200": "252 165 165","--color-error-300": "248 113 113","--color-error-400": "239 68 68","--color-error-500": "230 53 53","--color-error-600": "220 38 38","--color-error-700": "185 28 28","--color-error-800": "153 27 27","--color-error-900": "127 29 29","--color-error-950": "83 19 19",/* Success */"--color-success-0": "228 255 244","--color-success-50": "202 255 232","--color-success-100": "162 241 192","--color-success-200": "132 211 162","--color-success-300": "102 181 132","--color-success-400": "72 151 102","--color-success-500": "52 131 82","--color-success-600": "42 121 72","--color-success-700": "32 111 62","--color-success-800": "22 101 52","--color-success-900": "20 83 45","--color-success-950": "27 50 36",/* Warning */"--color-warning-0": "255 253 251","--color-warning-50": "255 249 245","--color-warning-100": "255 231 213","--color-warning-200": "254 205 170","--color-warning-300": "253 173 116","--color-warning-400": "251 149 75","--color-warning-500": "231 120 40","--color-warning-600": "215 108 31","--color-warning-700": "180 90 26","--color-warning-800": "130 68 23","--color-warning-900": "108 56 19","--color-warning-950": "84 45 18",/* Info */"--color-info-0": "236 248 254","--color-info-50": "199 235 252","--color-info-100": "162 221 250","--color-info-200": "124 207 248","--color-info-300": "87 194 246","--color-info-400": "50 180 244","--color-info-500": "13 166 242","--color-info-600": "11 141 205","--color-info-700": "9 115 168","--color-info-800": "7 90 131","--color-info-900": "5 64 93","--color-info-950": "3 38 56",/* Typography */"--color-typography-0": "254 254 255","--color-typography-50": "245 245 245","--color-typography-100": "229 229 229","--color-typography-200": "219 219 220","--color-typography-300": "212 212 212","--color-typography-400": "163 163 163","--color-typography-500": "140 140 140","--color-typography-600": "115 115 115","--color-typography-700": "82 82 82","--color-typography-800": "64 64 64","--color-typography-900": "38 38 39","--color-typography-950": "23 23 23",/* Outline */"--color-outline-0": "253 254 254","--color-outline-50": "243 243 243","--color-outline-100": "230 230 230","--color-outline-200": "221 220 219","--color-outline-300": "211 211 211","--color-outline-400": "165 163 163","--color-outline-500": "140 141 141","--color-outline-600": "115 116 116","--color-outline-700": "83 82 82","--color-outline-800": "65 65 65","--color-outline-900": "39 38 36","--color-outline-950": "26 23 23",/* Background */"--color-background-0": "255 255 255","--color-background-50": "246 246 246","--color-background-100": "242 241 241","--color-background-200": "220 219 219","--color-background-300": "213 212 212","--color-background-400": "162 163 163","--color-background-500": "142 142 142","--color-background-600": "116 116 116","--color-background-700": "83 82 82","--color-background-800": "65 64 64","--color-background-900": "39 38 37","--color-background-950": "24 23 24",/* Background Special */"--color-background-error": "254 241 241","--color-background-warning": "255 244 235","--color-background-success": "237 252 242","--color-background-muted": "247 248 247","--color-background-info": "235 248 254",/* Focus Ring Indicator */"--color-indicator-primary": "55 55 55","--color-indicator-info": "83 153 236","--color-indicator-error": "185 28 28",}),dark: vars({"--color-primary-0": "130 130 130","--color-primary-50": "148 148 148","--color-primary-100": "158 158 158","--color-primary-200": "179 179 179","--color-primary-300": "199 199 199","--color-primary-400": "230 230 230","--color-primary-500": "240 240 240","--color-primary-600": "250 250 250","--color-primary-700": "252 252 252","--color-primary-800": "253 253 253","--color-primary-900": "253 252 252","--color-primary-950": "253 252 252",/* Secondary */"--color-secondary-0": "11 12 12","--color-secondary-50": "24 23 23","--color-secondary-100": "39 38 38","--color-secondary-200": "63 64 64","--color-secondary-300": "81 82 82","--color-secondary-400": "94 95 95","--color-secondary-500": "114 115 115","--color-secondary-600": "175 176 176","--color-secondary-700": "219 219 219","--color-secondary-800": "231 232 232","--color-secondary-900": "241 242 242","--color-secondary-950": "254 255 255",/* Tertiary */"--color-tertiary-0": "84 49 18","--color-tertiary-50": "108 61 19","--color-tertiary-100": "130 73 23","--color-tertiary-200": "180 98 26","--color-tertiary-300": "215 117 31","--color-tertiary-400": "231 129 40","--color-tertiary-500": "251 157 75","--color-tertiary-600": "253 180 116","--color-tertiary-700": "254 209 170","--color-tertiary-800": "255 233 213","--color-tertiary-900": "255 242 229","--color-tertiary-950": "255 250 245",/* Error */"--color-error-0": "83 19 19","--color-error-50": "127 29 29","--color-error-100": "153 27 27","--color-error-200": "185 28 28","--color-error-300": "220 38 38","--color-error-400": "230 53 53","--color-error-500": "239 68 68","--color-error-600": "248 113 113","--color-error-700": "252 165 165","--color-error-800": "254 202 202","--color-error-900": "254 226 226","--color-error-950": "254 233 233",/* Success */"--color-success-0": "27 50 36","--color-success-50": "20 83 45","--color-success-100": "22 101 52","--color-success-200": "32 111 62","--color-success-300": "42 121 72","--color-success-400": "52 131 82","--color-success-500": "72 151 102","--color-success-600": "102 181 132","--color-success-700": "132 211 162","--color-success-800": "162 241 192","--color-success-900": "202 255 232","--color-success-950": "228 255 244",/* Warning */"--color-warning-0": "84 45 18","--color-warning-50": "108 56 19","--color-warning-100": "130 68 23","--color-warning-200": "180 90 26","--color-warning-300": "215 108 31","--color-warning-400": "231 120 40","--color-warning-500": "251 149 75","--color-warning-600": "253 173 116","--color-warning-700": "254 205 170","--color-warning-800": "255 231 213","--color-warning-900": "255 249 245","--color-warning-950": "255 253 251",/* Info */"--color-info-0": "3 38 56","--color-info-50": "5 64 93","--color-info-100": "7 90 131","--color-info-200": "9 115 168","--color-info-300": "11 141 205","--color-info-400": "13 166 242","--color-info-500": "50 180 244","--color-info-600": "87 194 246","--color-info-700": "124 207 248","--color-info-800": "162 221 250","--color-info-900": "199 235 252","--color-info-950": "236 248 254",/* Typography */"--color-typography-0": "23 23 23","--color-typography-50": "38 38 39","--color-typography-100": "64 64 64","--color-typography-200": "82 82 82","--color-typography-300": "115 115 115","--color-typography-400": "140 140 140","--color-typography-500": "163 163 163","--color-typography-600": "212 212 212","--color-typography-700": "219 219 220","--color-typography-800": "229 229 229","--color-typography-900": "245 245 245","--color-typography-950": "254 254 255",/* Outline */"--color-outline-0": "26 23 23","--color-outline-50": "39 38 36","--color-outline-100": "65 65 65","--color-outline-200": "83 82 82","--color-outline-300": "115 116 116","--color-outline-400": "140 141 141","--color-outline-500": "165 163 163","--color-outline-600": "211 211 211","--color-outline-700": "221 220 219","--color-outline-800": "230 230 230","--color-outline-900": "243 243 243","--color-outline-950": "253 254 254",/* Background */"--color-background-0": "18 18 18","--color-background-50": "39 38 37","--color-background-100": "65 64 64","--color-background-200": "83 82 82","--color-background-300": "116 116 116","--color-background-400": "142 142 142","--color-background-500": "162 163 163","--color-background-600": "213 212 212","--color-background-700": "220 219 219","--color-background-800": "242 241 241","--color-background-900": "246 246 246","--color-background-950": "254 254 254",/* Background Special */"--color-background-error": "66 43 43","--color-background-warning": "65 47 35","--color-background-success": "28 43 33","--color-background-muted": "51 51 51","--color-background-info": "26 40 46",/* Focus Ring Indicator */"--color-indicator-primary": "247 247 247","--color-indicator-info": "161 199 245","--color-indicator-error": "232 70 69",}),}
For Native
To add GluestackUIProvider, create a gluestack-ui-provider/index.tsx file inside components/ folder and paste the following code.
import React from "react"import { config } from "./config"import { ColorSchemeName, useColorScheme, View, ViewProps } from "react-native"import { OverlayProvider } from "@gluestack-ui/overlay"import { ToastProvider } from "@gluestack-ui/toast"import { colorScheme as colorSchemeNW } from "nativewind"type ModeType = "light" | "dark" | "system"const getColorSchemeName = (colorScheme: ColorSchemeName,mode: ModeType): "light" | "dark" => {if (mode === "system") {return colorScheme ?? "light"}return mode}export function GluestackUIProvider({mode = "light",...props}: {mode?: "light" | "dark" | "system"children?: React.ReactNodestyle?: ViewProps["style"]}) {const colorScheme = useColorScheme()const colorSchemeName = getColorSchemeName(colorScheme, mode)colorSchemeNW.set(mode)return (<Viewstyle={[config[colorSchemeName],{ flex: 1, height: "100%", width: "100%" },props.style,]}><OverlayProvider><ToastProvider>{props.children}</ToastProvider></OverlayProvider></View>)}
For Web
To add GluestackUIProvider, create a gluestack-ui-provider/index.web.tsx file inside components/ folder and paste the following code.
"use client"import React, { useEffect, useLayoutEffect } from "react"import { config } from "./config"import { OverlayProvider } from "@gluestack-ui/overlay"import { ToastProvider } from "@gluestack-ui/toast"import { setFlushStyles } from "@gluestack-ui/nativewind-utils/flush"import { script } from "./script"const variableStyleTagId = "nativewind-style"const createStyle = (styleTagId: string) => {const style = document.createElement("style")style.id = styleTagIdstyle.appendChild(document.createTextNode(""))return style}export const useSafeLayoutEffect =typeof window !== "undefined" ? useLayoutEffect : useEffectexport function GluestackUIProvider({mode = "light",...props}: {mode?: "light" | "dark" | "system"children?: React.ReactNode}) {let cssVariablesWithMode = ``Object.keys(config).forEach((configKey) => {cssVariablesWithMode +=configKey === "dark" ? `\n .dark {\n ` : `\n:root {\n`const cssVariables = Object.keys(config[configKey as keyof typeof config]).reduce((acc: string, curr: string) => {acc += `${curr}:${config[configKey as keyof typeof config][curr]}; `return acc}, "")cssVariablesWithMode += `${cssVariables} \n}`})setFlushStyles(cssVariablesWithMode)const handleMediaQuery = React.useCallback((e: MediaQueryListEvent) => {script(e.matches ? "dark" : "light")}, [])useSafeLayoutEffect(() => {if (mode !== "system") {const documentElement = document.documentElementif (documentElement) {documentElement.classList.add(mode)documentElement.classList.remove(mode === "light" ? "dark" : "light")documentElement.style.colorScheme = mode}}}, [mode])useSafeLayoutEffect(() => {if (mode !== "system") returnconst media = window.matchMedia("(prefers-color-scheme: dark)")media.addListener(handleMediaQuery)return () => media.removeListener(handleMediaQuery)}, [handleMediaQuery])useSafeLayoutEffect(() => {if (typeof window !== "undefined") {const documentElement = document.documentElementif (documentElement) {const head = documentElement.querySelector("head")let style = head?.querySelector(`[id='${variableStyleTagId}']`)if (!style) {style = createStyle(variableStyleTagId)style.innerHTML = cssVariablesWithModeif (head) head.appendChild(style)}}}}, [])return (<><scriptsuppressHydrationWarningdangerouslySetInnerHTML={{__html: `(${script.toString()})('${mode}')`,}}/><OverlayProvider><ToastProvider>{props.children}</ToastProvider></OverlayProvider></>)}
Step 3: Configure GluestackUIProvider in project
Wrap your app with GluestackUIProvider in App.tsx.
// App.tsxexport default function App() {return (<GluestackUIProvider>{/* Add your app code here */}</GluestackUIProvider>)}
Step 4: Server-side rendering (SSR) (Next.js Only).
It's also recommended to set up your server-side rendering (SSR) correctly. To do this, you will need to use the flush() function exported by the @gluestack-ui/nativewind-utils
App Router
Page Router
For Next.js App Routers we will create a new registry.tsx file in the root of your project and use the flush function from @gluestack-ui/nativewind-utils
"use client"import React, { useRef, useState } from "react"import { useServerInsertedHTML } from "next/navigation"import { StyleRegistry, createStyleRegistry } from "styled-jsx"import { Html, Head, Main, NextScript } from "next/document"// @ts-ignoreimport { AppRegistry } from "react-native-web"import { flush } from "@gluestack-ui/nativewind-utils/flush"export default function StyledJsxRegistry({children,}: {children: React.ReactNode}) {// Only create stylesheet once with lazy initial state// x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-stateconst [jsxStyleRegistry] = useState(() => createStyleRegistry())const isServerInserted = useRef(false)useServerInsertedHTML(() => {AppRegistry.registerComponent("Main", () => Main)const { getStyleElement } = AppRegistry.getApplication("Main")console.log(getStyleElement())if (!isServerInserted.current) {isServerInserted.current = trueconst styles = [getStyleElement(), jsxStyleRegistry.styles(), flush()]jsxStyleRegistry.flush()return <>{styles}</>}})return <StyleRegistry registry={jsxStyleRegistry}>{children}</StyleRegistry>}
- We also need to wrap children with StyledJsxRegistry in the layout.tsx file.
"use client"import { Inter } from "next/font/google"import "./globals.css"import { GluestackUIProvider } from "@/components/ui/gluestack-ui-provider"const inter = Inter({ subsets: ["latin"] })import StyledJsxRegistry from "./registry"export default function RootLayout({children,}: Readonly<{children: React.ReactNode}>) {return (<html lang="en"><body className={inter.className} style={{ display: "flex" }}><StyledJsxRegistry><GluestackUIProvider mode="light">{children}</GluestackUIProvider></StyledJsxRegistry></body></html>)}
For Next.js we will add this code in _document.tsx file.
import * as React from "react"import { Html, Head, Main, NextScript } from "next/document"import { AppRegistry } from "react-native-web"import { flush } from "@gluestack-ui/nativewind-utils/flush"function Document() {return (<Html className="gs" lang="en"><Head /><body><Main /><NextScript /></body></Html>)}Document.getInitialProps = async ({ renderPage }: any) => {AppRegistry.registerComponent("Main", () => Main)const { getStyleElement } = AppRegistry.getApplication("Main")const page = await renderPage()const styles = [getStyleElement(), flush()]return { ...page, styles: React.Children.toArray(styles) }}export default Document
Common issues
Expo app stuck in tailwindcss(ios) rebuilding... while running expo start command
In this case, you may have your app stored in a directory with a name containing spaces, such as 'Expo App', renaming it to just 'Expo-App' will resolve the issue.