Skip to content

What Should postSplashScreenTheme Point to When Your App Theme Is Defined Only in Compose?

When you build a Jetpack Compose app with themes defined entirely in Kotlin code using MaterialTheme, implementing the Splash Screen API creates a puzzle: what should postSplashScreenTheme point to? You have no XML theme to reference. This post gives you the direct answer.

The Direct Answer

postSplashScreenTheme should point to an XML theme that inherits from android:Theme.DeviceDefault.NoActionBar (or a Material theme if you use Material XML components). This XML theme serves as a bridge - it doesn’t need to duplicate your Compose MaterialTheme configuration, but it must exist because Android’s Activity lifecycle requires a valid XML theme before Compose code runs.

The minimal solution
<style name="Theme.App" parent="android:Theme.DeviceDefault.NoActionBar">
<!-- Leave empty - Compose handles all styling -->
</style>

Why This Confusion Exists

Many developers building “Compose-only” apps face this fundamental question. I found a Reddit discussion where multiple developers asked:

“What do I point postSplashScreenTheme to when my theme is defined via MaterialTheme in Compose?”

The confusion stems from a real architectural gap. Compose lets you define your entire UI theme in Kotlin, but the Splash Screen API operates at a lower level in Android’s Activity/Window system - which still expects XML themes.

What the Source Code Reveals

Looking at Android’s Theme.SplashScreen implementation provides the key insight:

Android's base splash theme (simplified)
<style name="Theme.SplashScreen" parent="android:Theme.DeviceDefault.NoActionBar">
<item name="android:windowBackground">@drawable/splash_screen_background</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="postSplashScreenTheme">@style/Theme.AppCompat.DayNight</item>
</style>

Notice that the base uses android:Theme.DeviceDefault.NoActionBar, not a Material theme. This means your postSplashScreenTheme doesn’t need to be a Material theme either.

Three Solutions Compared

res/values/themes.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Splash screen theme -->
<style name="Theme.App.Splash" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/splash_background</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/splash_icon</item>
<item name="windowSplashScreenAnimationDuration">200</item>
<item name="postSplashScreenTheme">@style/Theme.App</item>
</style>
<!-- Minimal theme for post-splash - inherits from Android default -->
<style name="Theme.App" parent="android:Theme.DeviceDefault.NoActionBar">
<!-- Empty - your Compose MaterialTheme handles everything -->
</style>
</resources>

When to use: Your app is 100% Compose with no XML-based Material components. This is the cleanest option.

Pros:

  • No Material Components dependency required
  • Minimal overhead
  • Compose handles all visual styling

Cons:

  • If you later add XML-based Views, you may need to change the parent

Option B: Material Theme Parent

res/values/themes.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.App.Splash" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/splash_background</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/splash_icon</item>
<item name="postSplashScreenTheme">@style/Theme.App</item>
</style>
<!-- Use Material3 parent if you have XML Material components -->
<style name="Theme.App" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Still empty - but Material foundation available -->
</style>
</resources>

When to use: Your app uses Material Components in XML (like BottomNavigationView in a mixed View/Compose setup), or you want Material default styling for system bars.

Pros:

  • Material styling for system UI elements
  • Required if using XML Material components
  • Consistent with Material design guidelines

Cons:

  • Adds Material Components library overhead
  • Slightly more complex inheritance chain

Option C: Empty Bridge Theme

res/values/themes.xml
<style name="Theme.App" parent="android:Theme.NoTitleBar">
<!-- Absolute minimal theme -->
</style>

When to use: Legacy projects transitioning to Compose, or when you need absolute minimal footprint.

Pros:

  • Smallest possible XML theme

Cons:

  • May cause status bar styling issues
  • Less future-proof

Complete Implementation

Here’s the complete setup for a Compose-only app:

Step 1: Add the Dependency

build.gradle.kts (Module: app)
dependencies {
implementation("androidx.core:core-splashscreen:1.0.1")
}

Step 2: Create XML Resources

res/values/themes.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.App.Splash" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/splash_background</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/splash_icon</item>
<item name="windowSplashScreenAnimationDuration">200</item>
<item name="postSplashScreenTheme">@style/Theme.App</item>
</style>
<style name="Theme.App" parent="android:Theme.DeviceDefault.NoActionBar">
<!-- Compose MaterialTheme takes over from here -->
</style>
</resources>
res/values/colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="splash_background">#FFFFFF</color>
</resources>
res/drawable/splash_icon.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:width="108dp"
android:height="108dp"
android:drawable="@mipmap/ic_launcher_round"
android:gravity="center" />
</layer-list>

Step 3: Update AndroidManifest

AndroidManifest.xml
<application
android:theme="@style/Theme.App.Splash">
<activity
android:name=".MainActivity"
android:theme="@style/Theme.App.Splash"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

Step 4: Install Splash Screen in MainActivity

MainActivity.kt
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// MUST call before super.onCreate()
val splashScreen = installSplashScreen()
super.onCreate(savedInstanceState)
// Optional: control when splash dismisses
var keepSplashVisible = true
splashScreen.setKeepOnScreenCondition { keepSplashVisible }
lifecycleScope.launch {
// Your initialization logic
initializeApp()
keepSplashVisible = false
}
setContent {
// Your Compose theme - this is where all styling lives
AppTheme {
NavHost(navController = rememberNavController()) {
// Your navigation graph
}
}
}
}
}

Step 5: Your Compose Theme (Unchanged)

ui/theme/Theme.kt
@Composable
fun AppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colorScheme = if (darkTheme) {
darkColorScheme(
primary = Purple80,
secondary = PurpleGrey80,
tertiary = Pink80
)
} else {
lightColorScheme(
primary = Purple40,
secondary = PurpleGrey40,
tertiary = Pink40
)
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
shapes = Shapes,
content = content
)
}

The Theme Transition Timeline

Understanding when each theme applies helps clarify why both are needed:

Theme Lifecycle
Time -->
┌─────────────────────────────────────────────────────────────────────┐
│ 1. App Launch │
│ └── System reads Theme.App.Splash from AndroidManifest │
│ │
│ 2. Splash Screen Visible │
│ └── Theme.SplashScreen attributes applied │
│ └── Shows splash_icon on splash_background │
│ │
│ 3. MainActivity.onCreate() called │
│ └── installSplashScreen() hooks into the existing splash │
│ │
│ 4. Splash transitions │
│ └── postSplashScreenTheme applied (Theme.App) │
│ └── Android switches to Theme.DeviceDefault.NoActionBar │
│ │
│ 5. setContent() called │
│ └── AppTheme {} Composable takes over │
│ └── MaterialTheme applies colors, typography, shapes │
│ │
│ 6. App running │
│ └── 100% Compose styling - XML theme invisible to user │
└─────────────────────────────────────────────────────────────────────┘

The XML theme (Theme.App) exists for only a brief moment between splash dismissal and Compose initialization. After that, your AppTheme Composable handles everything.

Common Mistakes to Avoid

Mistake 1: Pointing to a Compose Function

WRONG: postSplashScreenTheme cannot reference Compose
// You cannot do this:
// <item name="postSplashScreenTheme">???</item>
// There's no way to reference AppTheme() from XML

The XML theme system has no knowledge of Compose functions. You must have a real XML theme as the target.

Mistake 2: Using Theme.AppCompat Without AppCompatActivity

WRONG: AppCompat theme with ComponentActivity
<style name="Theme.App" parent="Theme.AppCompat.DayNight.NoActionBar">
<!-- WRONG if your Activity extends ComponentActivity -->
</style>

If your Activity extends ComponentActivity (common for Compose apps), don’t use Theme.AppCompat. Use android:Theme.DeviceDefault.NoActionBar instead.

Mistake 3: Duplicating Theme Configuration

UNNECESSARY: Don't duplicate Compose theme in XML
<style name="Theme.App" parent="android:Theme.DeviceDefault.NoActionBar">
<item name="colorPrimary">@color/purple_500</item>
<item name="colorSecondary">@color/teal_200</item>
<!-- These will be ignored - Compose overrides them -->
</style>

Your MaterialTheme in Compose will override any colors defined in XML. Don’t duplicate effort.

Mistake 4: Forgetting NoActionBar Suffix

WRONG: Action bar will appear briefly
<style name="Theme.App" parent="android:Theme.DeviceDefault">
<!-- Action bar flashes before Compose hides it -->
</style>

Without NoActionBar, you’ll see a brief action bar flash before Compose takes over.

Mistake 5: Not Handling Dark Mode

INCOMPLETE: Only light mode defined
<resources>
<color name="splash_background">#FFFFFF</color>
</resources>

Create a res/values-night/colors.xml for dark mode:

res/values-night/colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="splash_background">#1a1a1a</color>
</resources>

Decision Matrix

Your App SetupRecommended postSplashScreenTheme Parent
100% Composeandroid:Theme.DeviceDefault.NoActionBar
Compose + XML Material componentsTheme.Material3.DayNight.NoActionBar
Mixed View/Compose with AppCompatTheme.AppCompat.DayNight.NoActionBar
Minimal footprint priorityandroid:Theme.NoTitleBar

Summary

postSplashScreenTheme must point to an XML theme, even when your app’s visual theme is 100% Compose. The simplest solution is a minimal XML theme inheriting from android:Theme.DeviceDefault.NoActionBar.

Key points:

  • The XML theme is a bridge, not a duplicate of your Compose theme
  • Use android:Theme.DeviceDefault.NoActionBar for pure Compose apps
  • Use Theme.Material3.DayNight.NoActionBar only if you have XML Material components
  • Call installSplashScreen() before super.onCreate()
  • Let Compose MaterialTheme handle all user-facing styling

The hybrid approach isn’t a workaround - it’s the correct architecture. Android’s platform layer still expects XML themes for window configuration, while Compose handles everything the user sees.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments