Skip to main content

New Recipe

Inline Expo Config Plugins

Published on October 7th, 2025 by Frank Calise

View recipe

Latest Ignite Release

View on Github

Proven Recipes for your React Native apps

Starting from scratch doesn’t always make sense. That’s why we made the Ignite Cookbook for React Native – an easy way for developers to browse and share code snippets (or “recipes”) that actually work.

Spin Up Your App In Record Time

Stop reinventing the wheel on every project. Use the Ignite CLI to get your app started. Then, hop over to the Ignite Cookbook for React Native to browse for things like libraries in “cookie cutter” templates that work for almost any project. It’s the fastest way to get a React Native app off the ground.

Animation ImageAnimation ImageAnimation ImageAnimation ImageAnimation ImageAnimation Image

Find Quality Code When You Need It

The popular forum sites are great for finding code until you realize it’s based on an old version of React Native. Ignite Cookbook is a place for recipes that work as of the time they’re published – meaning, it worked when it was posted. And if it ever goes out of date, we’ll make sure the community knows on what version it was last working.

npx ignite-cli@latest new PizzaApp --workflow=cng --yes

mkdir plugins

├── app/
├── plugins/          # ← New folder for config plugins
├── app.config.ts
├── package.json
└── ...

import {
  ConfigPlugin,
  withStringsXml,
  AndroidConfig,
  withAndroidStyles,
} from "expo/config-plugins";

/**
 *
 * Expo Config Plugin to help address the double splash screen issue with `expo-splash-screen`
 * See more information about this issue here: https://github.com/expo/expo/issues/16084
 *
 * How it works:
 *   1) Replace the default splash screen with a transparent screen
 *   2) Set the splash screen status bar to translucent
 */
export const withSplashScreen: ConfigPlugin = (config) => {
  config = withAndroidSplashScreen(config);
  return config;
};

/**
 * Android implementation of the config plugin - the only platform needed for this plugin.
 * However, it is good practice to break up your config plugins from the exported
 * function into parts by platform. For example, if it was needed, we would also
 * add `withIosSplashScreen` for the iOS implementation.
 */
const withAndroidSplashScreen: ConfigPlugin = (config) => {
  config = withCustomStylesXml(config);
  config = withCustomStringsXml(config);
  return config;
};

/**
 * Modifies the `android/app/src/main/res/values/strings.xml` file to add the following string:
 *
 * <string name="expo_splash_screen_status_bar_translucent" translatable="false">true</string>
 */
const withCustomStringsXml: ConfigPlugin = (config) =>
  withStringsXml(config, (modConfig) => {
    modConfig.modResults = AndroidConfig.Strings.setStringItem(
      [
        {
          _: "true",
          $: {
            name: "expo_splash_screen_status_bar_translucent",
            translatable: "false",
          },
        },
      ],
      modConfig.modResults
    );
    return modConfig;
  });

/**
 * Modifies the `android/app/src/main/res/values/styles.xml` file to append the
 * the following to the Theme.App.SplashScreen style:
 *
 * <item name="android:windowIsTranslucent">true</item>
 */
const withCustomStylesXml: ConfigPlugin = (config) =>
  withAndroidStyles(config, async (modConfig) => {
    modConfig.modResults = AndroidConfig.Styles.assignStylesValue(modConfig.modResults, {
      add: true,
      name: "android:windowIsTranslucent",
      value: "true",
      parent: {
        name: "Theme.App.SplashScreen",
        parent: "AppTheme",
      },
    });
    return modConfig;
  });

module.exports = ({ config }: ConfigContext): Partial<ExpoConfig> => {
  const existingPlugins = config.plugins ?? [];

  return {
    ...config,
    plugins: [...existingPlugins, require("./plugins/withSplashScreen").withSplashScreen],
  };
};

npx expo prebuild --clean

<string name="expo_splash_screen_status_bar_translucent" translatable="false">true</string>

<style name="Theme.App.SplashScreen" parent="AppTheme">
  <!-- ... existing styles ... -->
  <item name="android:windowIsTranslucent">true</item>
</style>

// plugins/withCustomFonts.ts
export const withCustomFonts: ConfigPlugin = (config) => {
  // Implementation here
  return config;
};

// plugins/withDeepLinking.ts
export const withDeepLinking: ConfigPlugin = (config) => {
  // Implementation here
  return config;
};

// app.config.ts
module.exports = ({ config }: ConfigContext): Partial<ExpoConfig> => {
  const existingPlugins = config.plugins ?? [];

  return {
    ...config,
    plugins: [
      ...existingPlugins,
      require("./plugins/withSplashScreen").withSplashScreen,
      require("./plugins/withCustomFonts").withCustomFonts,
      require("./plugins/withDeepLinking").withDeepLinking,
    ],
  };
};

updated 40 seconds ago
Animation Image

Backed By A Community of React Native Experts

The Ignite Cookbook isn’t just a random group of code snippets. It’s a curated collection of usable code samples that the Infinite Red team’s used in their own React Native projects. Having worked with some of the biggest clients in the tech industry, we know a thing or two about keeping our code to a high standard. You can code confidently!

Animation ImageAnimation ImageAnimation ImageAnimation ImageAnimation ImageAnimation ImageAnimation ImageAnimation ImageAnimation ImageAnimation ImageAnimation Image