Getting Started
Quick Start
If you are looking to get started quickly, we recommend using the expo-starter project.
Manual Installation
If you have an existing project, or want to install shadcn-native manually, you can do so by following the steps below.
Install the core dependencies
These are the core dependencies you will need to install to use any of the components. Each component may ship its own dependencies.
expo
expo install @expo/browser-polyfill tailwind-variants@3.x.x tw-merge@3.x.x twrnc@4.x.x lucide-react-native@0.540.x nativewind@4.x.x react-native-reanimated@~3.x.x react-native-safe-area-context@5.x.x
expo install -D tailwindcss@^3.4.17 prettier-plugin-tailwindcss@^0.5.11
expo install @expo/router
expo install @expo/vector-icons
expo install @expo/linking
expo install @expo/constants
expo install @expo/dev-client
Configure Nativewind
Make sure to place your globals.css
file in the app
directory of your project.
Configure Themes
Themes are hard to get right. This is the approach we recommend. See the themes section for more information.
- Update your
tailwind.config.js
file to:
/** @type {import('tailwindcss').Config} */
export default {
darkMode: "class",
// Update this to your project's paths
content: ["./app/**/*.{ts,tsx}", "./components/**/*.{ts,tsx}"],
presets: [require("nativewind/preset")],
theme: {
extend: {
colors: {
border: "var(--border)",
input: "var(--input)",
ring: "var(--ring)",
background: "var(--background)",
foreground: "var(--foreground)",
primary: {
DEFAULT: "var(--primary)",
foreground: "var(--primary-foreground)",
},
secondary: {
DEFAULT: "var(--secondary)",
foreground: "var(--secondary-foreground)",
},
destructive: {
DEFAULT: "var(--destructive)",
foreground: "var(--destructive-foreground)",
},
success: {
DEFAULT: "var(--success)",
foreground: "var(--success-foreground)",
},
warning: {
DEFAULT: "var(--warning)",
foreground: "var(--warning-foreground)",
},
muted: {
DEFAULT: "var(--muted)",
foreground: "var(--muted-foreground)",
},
accent: {
DEFAULT: "var(--accent)",
foreground: "var(--accent-foreground)",
},
popover: {
DEFAULT: "var(--popover)",
foreground: "var(--popover-foreground)",
},
card: {
DEFAULT: "var(--card)",
foreground: "var(--card-foreground)",
},
sidebar: {
DEFAULT: "var(--sidebar-background)",
foreground: "var(--sidebar-foreground)",
primary: "var(--sidebar-primary)",
"primary-foreground": "var(--sidebar-primary-foreground)",
accent: "var(--sidebar-accent)",
"accent-foreground": "var(--sidebar-accent-foreground)",
border: "var(--sidebar-border)",
ring: "var(--sidebar-ring)",
},
},
borderRadius: {
xl: "calc(var(--radius) + 4px)",
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
full: "100%",
},
},
},
plugins: [],
};
- Update your
app/globals.css
file to:
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--radius: 0.625rem;
--background: #ffffff;
--foreground: #252525;
--card: #ffffff;
--card-foreground: #252525;
--popover: #ffffff;
--popover-foreground: #252525;
--primary: #343434;
--primary-foreground: #fbfbfb;
--secondary: #f7f7f7;
--secondary-foreground: #343434;
--success: #22c55e;
--warning: #eab308;
--muted: #f7f7f7;
--muted-foreground: #8e8e8e;
--accent: #f7f7f7;
--accent-foreground: #343434;
--destructive: #ef4444;
--border: #ebebeb;
--input: #ebebeb;
--ring: #b5b5b5;
--chart-1: #f97316;
--chart-2: #06b6d4;
--chart-3: #3b82f6;
--chart-4: #84cc16;
--chart-5: #f59e0b;
--sidebar: #fbfbfb;
--sidebar-foreground: #252525;
--sidebar-primary: #343434;
--sidebar-primary-foreground: #fbfbfb;
--sidebar-accent: #f7f7f7;
--sidebar-accent-foreground: #343434;
--sidebar-border: #ebebeb;
--sidebar-ring: #b5b5b5;
}
.dark:root {
--background: #252525;
--foreground: #fbfbfb;
--card: #343434;
--card-foreground: #fbfbfb;
--popover: #444444;
--popover-foreground: #fbfbfb;
--primary: #ebebeb;
--primary-foreground: #343434;
--secondary: #444444;
--secondary-foreground: #fbfbfb;
--muted: #444444;
--muted-foreground: #b5b5b5;
--accent: #5f5f5f;
--accent-foreground: #fbfbfb;
--destructive: #dc2626;
--success: #16a34a;
--warning: #ca8a04;
--border: rgba(255, 255, 255, 0.1);
--input: rgba(255, 255, 255, 0.15);
--ring: #8e8e8e;
--chart-1: #8b5cf6;
--chart-2: #10b981;
--chart-3: #f59e0b;
--chart-4: #ec4899;
--chart-5: #dc2626;
--sidebar: #343434;
--sidebar-foreground: #fbfbfb;
--sidebar-primary: #8b5cf6;
--sidebar-primary-foreground: #fbfbfb;
--sidebar-accent: #444444;
--sidebar-accent-foreground: #fbfbfb;
--sidebar-border: rgba(255, 255, 255, 0.1);
--sidebar-ring: #707070;
}
}
- Add the
theme.ts
file to your project:
import {useColorScheme} from "react-native";
export const theme = {
light: {
radius: "0.625rem",
background: "#ffffff",
foreground: "#252525",
card: "#ffffff",
cardForeground: "#252525",
popover: "#ffffff",
popoverForeground: "#252525",
primary: "#343434",
primaryForeground: "#fbfbfb",
secondary: "#f7f7f7",
secondaryForeground: "#343434",
success: "#22c55e",
warning: "#eab308",
muted: "#f7f7f7",
mutedForeground: "#8e8e8e",
accent: "#f7f7f7",
accentForeground: "#343434",
destructive: "#ef4444",
border: "#ebebeb",
input: "#ebebeb",
ring: "#b5b5b5",
chart1: "#f97316",
chart2: "#06b6d4",
chart3: "#3b82f6",
chart4: "#84cc16",
chart5: "#f59e0b",
sidebar: "#fbfbfb",
sidebarForeground: "#252525",
sidebarPrimary: "#343434",
sidebarPrimaryForeground: "#fbfbfb",
sidebarAccent: "#f7f7f7",
sidebarAccentForeground: "#343434",
sidebarBorder: "#ebebeb",
sidebarRing: "#b5b5b5",
},
dark: {
background: "#252525",
foreground: "#fbfbfb",
card: "#343434",
cardForeground: "#fbfbfb",
popover: "#444444",
popoverForeground: "#fbfbfb",
primary: "#ebebeb",
primaryForeground: "#343434",
secondary: "#444444",
secondaryForeground: "#fbfbfb",
muted: "#444444",
mutedForeground: "#b5b5b5",
accent: "#5f5f5f",
accentForeground: "#fbfbfb",
destructive: "#dc2626",
success: "#16a34a",
warning: "#ca8a04",
border: "rgba(255, 255, 255, 0.1)",
input: "rgba(255, 255, 255, 0.15)",
ring: "#8e8e8e",
chart1: "#8b5cf6",
chart2: "#10b981",
chart3: "#f59e0b",
chart4: "#ec4899",
chart5: "#dc2626",
sidebar: "#343434",
sidebarForeground: "#fbfbfb",
sidebarPrimary: "#8b5cf6",
sidebarPrimaryForeground: "#fbfbfb",
sidebarAccent: "#444444",
sidebarAccentForeground: "#fbfbfb",
sidebarBorder: "rgba(255, 255, 255, 0.1)",
sidebarRing: "#707070",
},
};
export const useTheme = () => {
const colorScheme = useColorScheme();
return theme[colorScheme || "light"];
};
// Suppress SVGElement error
class SVGElement {}
// @ts-ignore
globalThis.SVGElement = SVGElement;
- Optional: Theme your stack navigator:
import {useTheme} from "@/lib/utils/theme";
import {Stack, StatusBar} from "expo-router";
import {useColorScheme} from "react-native";
import "./global.css";
export default function RootLayout() {
const theme = useTheme();
const colorScheme = useColorScheme();
return (
<>
<StatusBar style={colorScheme === "dark" ? "light" : "dark"} />
<Stack
screenOptions={{
title: "Expo Starter",
contentStyle: {backgroundColor: theme.background},
headerTitleStyle: {color: theme.foreground},
headerStyle: {backgroundColor: theme.background},
}}
/>
</>
);
}
- Web You may need to manually add the dark class to the body element on web. Add the following to your root layout:
// Handle dark mode class for web
useEffect(() => {
if (Platform.OS === "web") {
// Type assertion for web platform where document is available
const doc = (globalThis as any).document;
if (doc) {
const root = doc.documentElement;
if (colorScheme === "dark") {
root.classList.add("dark");
} else {
root.classList.remove("dark");
}
}
}
}, [colorScheme]);
This theme is the base neutral theme from shadcn/ui. See more themes here shadcn/themes
See the themes section for more information.
Configure the Shadcn CLI
If you are adding components manually, you can skip this step.
Do not use the shadcn init command. It will break your configuration. We are working on our own CLI.
Create a components.json
file. This is a list of all the components you want to use.
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "",
"css": "app/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
}
For more information on the components.json
file, see the components.json
documentation.
Configure TypeScript
Update your tsconfig.json
file to:
{
"extends": "@react-native/typescript-config",
"compilerOptions": {
"target": "esnext",
"types": ["nativewind", "react-native"],
"jsxImportSource": "nativewind",
"jsx": "preserve",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"moduleResolution": "bundler",
"skipLibCheck": true,
"baseUrl": ".",
"paths": {
"@/*": ["./*"]
}
},
"include": [
"**/*.ts",
"**/*.tsx",
".expo/types/**/*.ts",
"expo-env.d.ts",
"nativewind-env.d.ts"
],
"exclude": ["node_modules"]
}
Add a Component
Test your setup by adding a component to your project.
pnpm
pnpm dlx shadcn@latest add https://shadcn-native.moveinready.casa/registry/button
All done! You can now start building your app.
Troubleshooting
Jest Cannot find module '@/lib/utils/theme'
If you are testing with Jest you may run into this error. To fix it add the following to your jest config:
moduleNameMapper: {
"^@/(.*)": "<rootDir>/registry/$1",
},
Styles not applying with Expo
Restart your Expo server.
expo start --clear
Styles not applying (React Native or Expo)
If your styles still aren’t applying, make sure you are importing the globals.css
file in your root layout.
Dark mode not working (web)
Add the following to your root layout:
// Handle dark mode class for web
useEffect(() => {
if (Platform.OS === "web") {
// Type assertion for web platform where document is available
const doc = (globalThis as any).document;
if (doc) {
const root = doc.documentElement;
if (colorScheme === "dark") {
root.classList.add("dark");
} else {
root.classList.remove("dark");
}
}
}
}, [colorScheme]);