Customization

Styling

Get started with styling your app.

To build the user web interface TurboStarter comes with Nativewind pre-configured.

Why Nativewind?

Nativewind is basically a Tailwind CSS for mobile apps. It gives you a way to style your app with Tailwind CSS utilities and classes.

Tailwind configuration

In the tooling/tailwind/config directory you will find shared Tailwind CSS configuration files. To change some global styles you can edit the files in this folder.

Here is an example of a shared Tailwind configuration file:

tooling/tailwind/config/base.ts
import type { Config } from "tailwindcss";
 
export default {
  darkMode: "class",
  content: ["src/**/*.{ts,tsx}"],
  theme: {
    extend: {
      colors: {
        ...
        primary: {
          DEFAULT: colorVariable("--colors-primary", true),
          foreground: colorVariable("--colors-primary-foreground", true),
        },
        secondary: {
          DEFAULT: colorVariable("--colors-secondary", true),
          foreground: colorVariable("--colors-secondary-foreground", true),
        },
        success: {
          DEFAULT: colorVariable("--colors-success", true),
          foreground: colorVariable("--colors-success-foreground", true),
        },
        ...
      },
    },
  },
  plugins: [animate, containerQueries, typography],
} satisfies Config;

For the colors part, we bet stricly on CSS Variables in HSL format to allow for easy theme management without a need for any JavaScript.

Also, each app has its own tailwind.config.ts file which extends the shared config and allows you to override the global styles.

Here is an example of an app's tailwind.config.ts file:

apps/mobile/tailwind.config.ts
import type { Config } from "tailwindcss";
import nativewind from "nativewind/preset";
import { hairlineWidth } from "nativewind/theme";
 
import baseConfig from "@turbostarter/tailwind-config/mobile";
 
export default {
  // We need to append the path to the UI package to the content array so that
  // those classes are included correctly.
  content: [
    ...baseConfig.content,
    "../../packages/ui/{shared,mobile}/src/**/*.{ts,tsx}",
  ],
  presets: [baseConfig, nativewind],
  theme: {
    extend: {
      fontFamily: {
        sans: ["DMSans_400Regular"],
        mono: ["DMMono_400Regular"],
      },
      borderWidth: {
        hairline: hairlineWidth(),
      },
    },
  },
} satisfies Config;

That way we can have a separation of concerns and a clear structure for the Tailwind CSS configuration.

Themes

TurboStarter comes with 10+ predefined themes which you can use to quickly change the look and feel of your app.

They're defined in packages/ui/shared/src/styles/themes directory. Each theme is a set of variables that can be overridden:

packages/ui/shared/src/styles/themes/orange.ts
export const orange = {
  light: {
    background: [0, 0, 1],
    foreground: [240, 0.1, 0.039],
    card: [0, 0, 1],
    "card-foreground": [240, 0.1, 0.039],
    ...
  }
} satisfies ThemeColors;

Each variable is stored as a HSL array, which is then converted to a CSS variable. That way we can ensure full type-safety and reuse themes across parts of our apps (e.g. use the same theme in emails).

Feel free to add your own themes or override the existing ones to match your brand's identity.

To apply a theme to your app, we're declaring a theme provider, which is a wrapper around the app that passes the correct variables to the styles that will be used in the components and screens. It's located at providers/theme.tsx:

apps/mobile/src/providers/theme.tsx
export default function ThemeProvider({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <NavigationThemeProvider value={isDark ? DarkTheme : DefaultTheme}>
      <View style={colors[config.color][resolvedTheme]} className="flex-1">
        {children}
      </View>
    </NavigationThemeProvider>
  );
}

Dark mode

TurboStarter comes with a built-in dark mode support.

Each theme has a corresponding dark mode variables which are used to change the theme to its dark mode counterpart.

packages/ui/shared/src/styles/themes/orange.ts
export const orange = {
  light: {},
  dark: {
    background: [0, 0, 1],
    foreground: [240, 0.1, 0.039],
    card: [0, 0, 1],
    "card-foreground": [240, 0.1, 0.039],
    ...
  }
} satisfies ThemeColors;

Nativewind takes care of adding the dark class to the root of our app as well as reading the user's preferences via useColorScheme hook. That way you can put full focus on the features and just change the colors if you need to customize the theme.

Also, you can define the default theme mode and color in app configuration.

Last updated on

On this page

Ship your startup everywhere. In minutes.