Skip to content

Jetpack Compose Theme — Complete Guide

DodaTech Updated 2026-06-24 2 min read

In this tutorial, you'll learn about Jetpack Compose Theme. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

The Problem

Your Compose app looks like a default Material skeleton, dark mode doesn't work, or custom colors aren't applied consistently across components.

Wrong Approach ❌

@Composable
fun BadApp() {
    // No theme — default Material colors everywhere
    MyApp()
}

// Custom colors hardcoded in every composable
@Composable
fun BadButton() {
    Button(
        onClick = {},
        colors = ButtonDefaults.buttonColors(
            containerColor = Color(0xFF6200EE) // Hardcoded!
        )
    ) { Text("Click") }
}

Output: Inconsistent styling, broken dark mode, duplicated color values.

Right Approach ✅

// Custom color scheme
private val LightColors = lightColorScheme(
    primary = Purple40,
    secondary = PurpleGrey40,
    tertiary = Pink40,
    background = Color(0xFFFFFBFE)
)

private val DarkColors = darkColorScheme(
    primary = Purple80,
    secondary = PurpleGrey80,
    tertiary = Pink80,
    background = Color(0xFF1C1B1F)
)

@Composable
fun DodaTechTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    val colorScheme = if (darkTheme) DarkColors else LightColors

    MaterialTheme(
        colorScheme = colorScheme,
        typography = Typography(
            headlineLarge = TextStyle(fontFamily = FontFamily.SansSerif, fontWeight = FontWeight.Bold),
            bodyLarge = TextStyle(fontSize = 16.sp)
        ),
        content = content
    )
}

Output: Consistent theming with automatic dark mode support.

Prevention

  • Wrap your app in a custom MaterialTheme with colorScheme and typography.
  • Define separate lightColorScheme and darkColorScheme for dark mode.
  • Use MaterialTheme.colorScheme.primary instead of hardcoded colors.
  • Define Typography once — override per-component when needed.

Common Mistakes with compose theme

  1. Using foldl instead of foldl' causing stack overflow on large lists
  2. Forgetting deriving (Show, Eq) on custom data types needed for debugging
  3. Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable

These mistakes appear frequently in real-world Android code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### How do I add custom colors to the theme?

Extend ColorScheme with additional properties using a wrapper composable, or define top-level val colors and use them directly. Material 3 has slots for most use-cases.

### What is the difference between Material 2 and Material 3 theming?

Material 3 uses MaterialTheme with colorScheme (not colors), dynamic color support on Android 12+, and updated component styling. Prefer Material 3 for new projects.

### Can I use SystemUI dynamic colors in Compose?

Yes. On Android 12+, use dynamicLightColorScheme(context) and dynamicDarkColorScheme(context) to generate a color scheme from the system wallpaper.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro