Theming is the secret sauce for creating polished, professional apps. With Compose Multiplatform, you can define a unified design system that adapts to Android, iOS, desktop, and web—while still allowing platform-specific tweaks. This guide covers Material Design theming, dark mode, and adaptive styling strategies for KMP apps.


1. Building a Unified Theme with Material Design

Compose Multiplatform uses Material Design 3 by default, ensuring consistency across platforms.

Basic Theme Setup

@Composable  
fun MyAppTheme(content: @Composable () -> Unit) {  
    MaterialTheme(  
        colorScheme = lightColorScheme(), // Default M3 colors  
        typography = Typography(),  
        shapes = Shapes(),  
        content = content  
    )  
}  

// Usage  
@Composable  
fun App() {  
    MyAppTheme {  
        HomeScreen()  
    }  
}  

2. Customizing Colors, Typography, and Shapes

Color Schemes

Define light/dark palettes for brand consistency:

private val LightColors = lightColorScheme(  
    primary = Color(0xFF6200EA), // Purple  
    secondary = Color(0xFF03DAC6), // Teal  
    background = Color.White  
)  

private val DarkColors = darkColorScheme(  
    primary = Color(0xFFBB86FC), // Light purple  
    secondary = Color(0xFF03DAC6),  
    background = Color(0xFF121212) // Dark gray  
)  

Dark Mode Support

@Composable  
fun MyAppTheme(  
    darkTheme: Boolean = isSystemInDarkTheme(),  
    content: @Composable () -> Unit  
) {  
    val colors = if (darkTheme) DarkColors else LightColors  
    MaterialTheme(colorScheme = colors, /*...*/)  
}  

Pro Tip: Use isSystemInDarkTheme() for automatic dark/light switching.


3. Platform-Specific Styling

Adjust designs for iOS, Android, or desktop without breaking shared logic.

Detecting Platforms

import org.jetbrains.compose.ui.platform.Platform  

val isAndroid = Platform.OS == "Android"  
val isIOS = Platform.OS == "iOS"  

Platform-Adaptive Components

@Composable  
fun PlatformButton(label: String) {  
    val color = when (Platform.OS) {  
        "Android" -> Color.Blue  
        "iOS" -> Color.Gray  
        else -> MaterialTheme.colorScheme.primary  
    }  

    Button(colors = ButtonDefaults.buttonColors(color)) {  
        Text(label)  
    }  
}  

4. Advanced Theming Strategies

Typography System

val AppTypography = Typography(  
    headlineLarge = TextStyle(  
        fontSize = 30.sp,  
        fontWeight = FontWeight.Bold  
    ),  
    bodyMedium = TextStyle(fontSize = 16.sp)  
)  

// Usage  
Text("Title", style = MaterialTheme.typography.headlineLarge)  

Shape Customization

val AppShapes = Shapes(  
    small = RoundedCornerShape(4.dp), // Buttons  
    medium = RoundedCornerShape(8.dp), // Cards  
    large = RoundedCornerShape(16.dp) // Dialogs  
)  

5. Centralized Theme Management

Keep styles consistent with a theme manager:

object ThemeManager {  
    val colors: ColorScheme  
        get() = if (isSystemInDarkTheme()) DarkColors else LightColors  

    val typography: Typography = AppTypography  
    val shapes: Shapes = AppShapes  
}  

// Apply everywhere  
MaterialTheme(  
    colorScheme = ThemeManager.colors,  
    typography = ThemeManager.typography,  
    shapes = ThemeManager.shapes  
)  

Key Takeaways

  1. Use MaterialTheme for cross-platform design consistency.
  2. Support dark mode with isSystemInDarkTheme().
  3. Use Platform.OS checks for platform-specific tweaks.
  4. Centralize styles with a theme manager for easy maintenance.
  5. Link to Material Design 3 docs for authority.

0 0 votes
Article Rating

Leave a Reply

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x