Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    sooom1627

    expo-tailwind-setup

    sooom1627/expo-tailwind-setup
    Design

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Set up Tailwind CSS v4 in Expo with react-native-css and NativeWind v5 for universal styling

    SKILL.md

    Tailwind CSS Setup for Expo with react-native-css

    This guide covers setting up Tailwind CSS v4 in Expo using react-native-css and NativeWind v5 for universal styling across iOS, Android, and Web.

    Overview

    This setup uses:

    • Tailwind CSS v4 - Modern CSS-first configuration
    • react-native-css - CSS runtime for React Native
    • NativeWind v5 - Metro transformer for Tailwind in React Native
    • @tailwindcss/postcss - PostCSS plugin for Tailwind v4

    Installation

    # Install dependencies
    npx expo install tailwindcss@^4 nativewind@5.0.0-preview.2 react-native-css@0.0.0-nightly.5ce6396 @tailwindcss/postcss tailwind-merge clsx
    

    Add resolutions for lightningcss compatibility:

    // package.json
    {
      "resolutions": {
        "lightningcss": "1.30.1"
      }
    }
    
    • autoprefixer is not needed in Expo because of lightningcss
    • postcss is included in expo by default

    Configuration Files

    Metro Config

    Create or update metro.config.js:

    // metro.config.js
    const { getDefaultConfig } = require("expo/metro-config");
    const { withNativewind } = require("nativewind/metro");
    
    /** @type {import('expo/metro-config').MetroConfig} */
    const config = getDefaultConfig(__dirname);
    
    module.exports = withNativewind(config, {
      // inline variables break PlatformColor in CSS variables
      inlineVariables: false,
      // We add className support manually
      globalClassNamePolyfill: false,
    });
    

    PostCSS Config

    Create postcss.config.mjs:

    // postcss.config.mjs
    export default {
      plugins: {
        "@tailwindcss/postcss": {},
      },
    };
    

    Global CSS

    Create src/global.css:

    @import "tailwindcss/theme.css" layer(theme);
    @import "tailwindcss/preflight.css" layer(base);
    @import "tailwindcss/utilities.css";
    
    /* Platform-specific font families */
    @media android {
      :root {
        --font-mono: monospace;
        --font-rounded: normal;
        --font-serif: serif;
        --font-sans: normal;
      }
    }
    
    @media ios {
      :root {
        --font-mono: ui-monospace;
        --font-serif: ui-serif;
        --font-sans: system-ui;
        --font-rounded: ui-rounded;
      }
    }
    

    IMPORTANT: No Babel Config Needed

    With Tailwind v4 and NativeWind v5, you do NOT need a babel.config.js for Tailwind. Remove any NativeWind babel presets if present:

    // DELETE babel.config.js if it only contains NativeWind config
    // The following is NO LONGER needed:
    // module.exports = function (api) {
    //   api.cache(true);
    //   return {
    //     presets: [
    //       ["babel-preset-expo", { jsxImportSource: "nativewind" }],
    //       "nativewind/babel",
    //     ],
    //   };
    // };
    

    CSS Component Wrappers

    Since react-native-css requires explicit CSS element wrapping, create reusable components:

    Main Components (src/tw/index.tsx)

    import React from "react";
    
    import {
      Pressable as RNPressable,
      ScrollView as RNScrollView,
      Text as RNText,
      TextInput as RNTextInput,
      TouchableHighlight as RNTouchableHighlight,
      View as RNView,
      StyleSheet,
    } from "react-native";
    
    import { Link as RouterLink } from "expo-router";
    
    import {
      useCssElement,
      useNativeVariable as useFunctionalVariable,
    } from "react-native-css";
    import Animated from "react-native-reanimated";
    
    // CSS-enabled Link
    export const Link = (
      props: React.ComponentProps<typeof RouterLink> & { className?: string },
    ) => {
      return useCssElement(RouterLink, props, { className: "style" });
    };
    
    Link.Trigger = RouterLink.Trigger;
    Link.Menu = RouterLink.Menu;
    Link.MenuAction = RouterLink.MenuAction;
    Link.Preview = RouterLink.Preview;
    
    // CSS Variable hook
    export const useCSSVariable =
      process.env.EXPO_OS !== "web"
        ? useFunctionalVariable
        : (variable: string) => `var(${variable})`;
    
    // View
    export type ViewProps = React.ComponentProps<typeof RNView> & {
      className?: string;
    };
    
    export const View = (props: ViewProps) => {
      return useCssElement(RNView, props, { className: "style" });
    };
    View.displayName = "CSS(View)";
    
    // Text
    export const Text = (
      props: React.ComponentProps<typeof RNText> & { className?: string },
    ) => {
      return useCssElement(RNText, props, { className: "style" });
    };
    Text.displayName = "CSS(Text)";
    
    // ScrollView
    export const ScrollView = (
      props: React.ComponentProps<typeof RNScrollView> & {
        className?: string;
        contentContainerClassName?: string;
      },
    ) => {
      return useCssElement(RNScrollView, props, {
        className: "style",
        contentContainerClassName: "contentContainerStyle",
      });
    };
    ScrollView.displayName = "CSS(ScrollView)";
    
    // Pressable
    export const Pressable = (
      props: React.ComponentProps<typeof RNPressable> & { className?: string },
    ) => {
      return useCssElement(RNPressable, props, { className: "style" });
    };
    Pressable.displayName = "CSS(Pressable)";
    
    // TextInput
    export const TextInput = (
      props: React.ComponentProps<typeof RNTextInput> & { className?: string },
    ) => {
      return useCssElement(RNTextInput, props, { className: "style" });
    };
    TextInput.displayName = "CSS(TextInput)";
    
    // AnimatedScrollView
    export const AnimatedScrollView = (
      props: React.ComponentProps<typeof Animated.ScrollView> & {
        className?: string;
        contentClassName?: string;
        contentContainerClassName?: string;
      },
    ) => {
      return useCssElement(Animated.ScrollView, props, {
        className: "style",
        contentClassName: "contentContainerStyle",
        contentContainerClassName: "contentContainerStyle",
      });
    };
    
    // TouchableHighlight with underlayColor extraction
    function XXTouchableHighlight(
      props: React.ComponentProps<typeof RNTouchableHighlight>,
    ) {
      const { underlayColor, ...style } = StyleSheet.flatten(props.style) || {};
      return (
        <RNTouchableHighlight
          underlayColor={underlayColor}
          {...props}
          style={style}
        />
      );
    }
    
    export const TouchableHighlight = (
      props: React.ComponentProps<typeof RNTouchableHighlight>,
    ) => {
      return useCssElement(XXTouchableHighlight, props, { className: "style" });
    };
    TouchableHighlight.displayName = "CSS(TouchableHighlight)";
    

    Image Component (src/tw/image.tsx)

    import React from "react";
    
    import { StyleSheet } from "react-native";
    
    import { Image as RNImage } from "expo-image";
    
    import { useCssElement } from "react-native-css";
    import Animated from "react-native-reanimated";
    
    const AnimatedExpoImage = Animated.createAnimatedComponent(RNImage);
    
    export type ImageProps = React.ComponentProps<typeof Image>;
    
    function CSSImage(props: React.ComponentProps<typeof AnimatedExpoImage>) {
      // @ts-expect-error: Remap objectFit style to contentFit property
      const { objectFit, objectPosition, ...style } =
        StyleSheet.flatten(props.style) || {};
    
      return (
        <AnimatedExpoImage
          contentFit={objectFit}
          contentPosition={objectPosition}
          {...props}
          source={
            typeof props.source === "string" ? { uri: props.source } : props.source
          }
          // @ts-expect-error: Style is remapped above
          style={style}
        />
      );
    }
    
    export const Image = (
      props: React.ComponentProps<typeof CSSImage> & { className?: string },
    ) => {
      return useCssElement(CSSImage, props, { className: "style" });
    };
    
    Image.displayName = "CSS(Image)";
    

    Animated Components (src/tw/animated.tsx)

    import RNAnimated from "react-native-reanimated";
    
    import * as TW from "./index";
    
    export const Animated = {
      ...RNAnimated,
      View: RNAnimated.createAnimatedComponent(TW.View),
    };
    

    Usage

    Import CSS-wrapped components from your tw directory:

    import { Image, ScrollView, Text, View } from "@/tw";
    
    export default function MyScreen() {
      return (
        <ScrollView className="flex-1 bg-white">
          <View className="gap-4 p-4">
            <Text className="text-xl font-bold text-gray-900">Hello Tailwind!</Text>
            <Image
              className="h-48 w-full rounded-lg object-cover"
              source={{ uri: "https://example.com/image.jpg" }}
            />
          </View>
        </ScrollView>
      );
    }
    

    Custom Theme Variables

    Add custom theme variables in your global.css using @theme:

    @layer theme {
      @theme {
        /* Custom fonts */
        --font-rounded: "SF Pro Rounded", sans-serif;
    
        /* Custom line heights */
        --text-xs--line-height: calc(1em / 0.75);
        --text-sm--line-height: calc(1.25em / 0.875);
        --text-base--line-height: calc(1.5em / 1);
    
        /* Custom leading scales */
        --leading-tight: 1.25em;
        --leading-snug: 1.375em;
        --leading-normal: 1.5em;
      }
    }
    

    Platform-Specific Styles

    Use platform media queries for platform-specific styling:

    @media ios {
      :root {
        --font-sans: system-ui;
        --font-rounded: ui-rounded;
      }
    }
    
    @media android {
      :root {
        --font-sans: normal;
        --font-rounded: normal;
      }
    }
    

    Apple System Colors with CSS Variables

    Create a CSS file for Apple semantic colors:

    /* src/css/sf.css */
    @layer base {
      html {
        color-scheme: light;
      }
    }
    
    :root {
      /* Accent colors with light/dark mode */
      --sf-blue: light-dark(rgb(0 122 255), rgb(10 132 255));
      --sf-green: light-dark(rgb(52 199 89), rgb(48 209 89));
      --sf-red: light-dark(rgb(255 59 48), rgb(255 69 58));
    
      /* Gray scales */
      --sf-gray: light-dark(rgb(142 142 147), rgb(142 142 147));
      --sf-gray-2: light-dark(rgb(174 174 178), rgb(99 99 102));
    
      /* Text colors */
      --sf-text: light-dark(rgb(0 0 0), rgb(255 255 255));
      --sf-text-2: light-dark(rgb(60 60 67 / 0.6), rgb(235 235 245 / 0.6));
    
      /* Background colors */
      --sf-bg: light-dark(rgb(255 255 255), rgb(0 0 0));
      --sf-bg-2: light-dark(rgb(242 242 247), rgb(28 28 30));
    }
    
    /* iOS native colors via platformColor */
    @media ios {
      :root {
        --sf-blue: platformColor(systemBlue);
        --sf-green: platformColor(systemGreen);
        --sf-red: platformColor(systemRed);
        --sf-gray: platformColor(systemGray);
        --sf-text: platformColor(label);
        --sf-text-2: platformColor(secondaryLabel);
        --sf-bg: platformColor(systemBackground);
        --sf-bg-2: platformColor(secondarySystemBackground);
      }
    }
    
    /* Register as Tailwind theme colors */
    @layer theme {
      @theme {
        --color-sf-blue: var(--sf-blue);
        --color-sf-green: var(--sf-green);
        --color-sf-red: var(--sf-red);
        --color-sf-gray: var(--sf-gray);
        --color-sf-text: var(--sf-text);
        --color-sf-text-2: var(--sf-text-2);
        --color-sf-bg: var(--sf-bg);
        --color-sf-bg-2: var(--sf-bg-2);
      }
    }
    

    Then use in components:

    <Text className="text-sf-text">Primary text</Text>
    <Text className="text-sf-text-2">Secondary text</Text>
    <View className="bg-sf-bg">...</View>
    

    Using CSS Variables in JavaScript

    Use the useCSSVariable hook:

    import { useCSSVariable } from "@/tw";
    
    function MyComponent() {
      const blue = useCSSVariable("--sf-blue");
    
      return <View style={{ borderColor: blue }} />;
    }
    

    Key Differences from NativeWind v4 / Tailwind v3

    1. No babel.config.js - Configuration is now CSS-first
    2. PostCSS plugin - Uses @tailwindcss/postcss instead of tailwindcss
    3. CSS imports - Use @import "tailwindcss/..." instead of @tailwind directives
    4. Theme config - Use @theme in CSS instead of tailwind.config.js
    5. Component wrappers - Must wrap components with useCssElement for className support
    6. Metro config - Use withNativewind with different options (inlineVariables: false)

    Troubleshooting

    Styles not applying

    1. Ensure you have the CSS file imported in your app entry
    2. Check that components are wrapped with useCssElement
    3. Verify Metro config has withNativewind applied

    Platform colors not working

    1. Use platformColor() in @media ios blocks
    2. Fall back to light-dark() for web/Android

    TypeScript errors

    Add className to component props:

    type Props = React.ComponentProps<typeof RNView> & { className?: string };
    
    Recommended Servers
    Hugeicons MCP Server
    Hugeicons MCP Server
    Miro
    Miro
    Vercel Grep
    Vercel Grep
    Repository
    sooom1627/linkcache
    Files