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.
<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:
<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
Option A: Minimal Base Theme (Recommended)
<?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
<?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
<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
dependencies { implementation("androidx.core:core-splashscreen:1.0.1")}Step 2: Create XML Resources
<?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><?xml version="1.0" encoding="utf-8"?><resources> <color name="splash_background">#FFFFFF</color></resources><?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
<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
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)
@Composablefun 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:
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
// You cannot do this:// <item name="postSplashScreenTheme">???</item>// There's no way to reference AppTheme() from XMLThe 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
<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
<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
<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
<resources> <color name="splash_background">#FFFFFF</color></resources>Create a res/values-night/colors.xml for dark mode:
<?xml version="1.0" encoding="utf-8"?><resources> <color name="splash_background">#1a1a1a</color></resources>Decision Matrix
| Your App Setup | Recommended postSplashScreenTheme Parent |
|---|---|
| 100% Compose | android:Theme.DeviceDefault.NoActionBar |
| Compose + XML Material components | Theme.Material3.DayNight.NoActionBar |
| Mixed View/Compose with AppCompat | Theme.AppCompat.DayNight.NoActionBar |
| Minimal footprint priority | android: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.NoActionBarfor pure Compose apps - Use
Theme.Material3.DayNight.NoActionBaronly if you have XML Material components - Call
installSplashScreen()beforesuper.onCreate() - Let Compose
MaterialThemehandle 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:
- 👨💻 Reddit: postSplashScreenTheme in Compose-only apps
- 👨💻 Android Splash Screen API Documentation
- 👨💻 Theme.SplashScreen Source Code
- 👨💻 Material3 Theming Guide
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments