Skip to content

Expert: features and shipping · Permissions, Material 3 and polish · topic 36 of 50 · 30 min

Material 3 theming

Explanation

Material Design 3 (Material You) is Google's design system. In Compose, MaterialTheme provides a colorScheme, typography and shapes that every component uses. Define light and dark colour schemes for your brand, optionally use dynamic colour from the user's wallpaper on Android 12+, and always read colours from MaterialTheme.colorScheme instead of hard-coding them.

What is a design system?

A design system is a set of rules and ready components that make an app look consistent: which colours mean what, which font sizes to use, how rounded corners are. Material Design is Google's design system; version 3 (also called Material You) is the current one, and Compose's material3 library implements it.

The theme

kotlin
private val LightColors = lightColorScheme(
    primary = Color(0xFF00695C),          // brand teal
    secondary = Color(0xFFFF8F00),        // saffron accent
)
private val DarkColors = darkColorScheme(
    primary = Color(0xFF4DB6AC),
    secondary = Color(0xFFFFB74D),
)

@Composable
fun ShopTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
    MaterialTheme(
        colorScheme = if (darkTheme) DarkColors else LightColors,
        typography = Typography(),        // default Material 3 type scale
        content = content,
    )
}
The template generates a Theme.kt like this. Everything inside ShopTheme uses these values.

A colour scheme is more than a few colours. Material 3 defines roles: primary, onPrimary (text on primary), primaryContainer, secondary, surface, onSurface, error and more. Components pick the right role automatically, so a Button uses primary with onPrimary text, and a Card uses a surface colour.

Use roles, not raw colours

kotlin
// Good: follows the theme, works in dark mode
Text("Rs 499", color = MaterialTheme.colorScheme.primary)
Surface(color = MaterialTheme.colorScheme.secondaryContainer) { Text("Offer") }

// Avoid: breaks dark mode and rebranding
Text("Rs 499", color = Color(0xFF00695C))
Change the brand colour in one place and the whole app follows.

Dark mode is not just "invert the colours". Material 3 dark schemes use dark grey surfaces rather than pure black, and lighter versions of your brand colours so they stay readable. Define both schemes from the start; adding dark mode later to an app full of hard-coded colours is painful.

Typography and shapes

The type scale has roles like displayLarge, headlineMedium, titleLarge, bodyMedium and labelSmall. Use them through MaterialTheme.typography.titleLarge instead of picking font sizes by hand. Shapes (small, medium, large corner styles) work the same way through MaterialTheme.shapes. You can load your own fonts (for example a font with good Devanagari support) into the Typography.

Dynamic colour

On Android 12 (API 31) and later, the system can generate a colour scheme from the user's wallpaper. Apps can opt in, so they feel part of the user's phone. Many brands keep their own colours instead; it is a product choice.

kotlin
val colorScheme = when {
    Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ->
        if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
    darkTheme -> DarkColors
    else -> LightColors
}
Fall back to your own schemes on older Android versions.

Building a scheme

Picking a full, accessible set of colour roles by hand is hard. The Material Theme Builder (linked from m3.material.io) generates light and dark schemes from one brand colour and exports Compose code.

Think of it like this: A theme is like a company's uniform policy. Instead of each employee choosing their own shirt colour, the policy says: managers wear navy, staff wear teal, name tags are white. Change the policy once, and everyone's outfit updates.

Common mistakes

  • Hard-coded colours scattered through screens: dark mode looks broken.
  • Low contrast text, such as light grey on white, which is hard to read outdoors in sunlight. Use on-colours (onSurface, onPrimary).
  • Forgetting to wrap previews in your theme, so previews look different from the app.
  • Mixing material (Material 2) and material3 components in one screen.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Material 3 theming · 1/6

Material 3 = Material You

Material three is Google's design system. Compose implements it in the material three library.

Prefer a video by a teacher? Find free videos on “material 3 theming jetpack compose color scheme dynamic color” on YouTube ↗

In real life: A festive sale theme

An online store wants a special look for its Diwali sale. Because every screen uses MaterialTheme roles, the team ships a temporary colour scheme with deep maroon as primary and gold as secondary, controlled by a remote flag. For two weeks the entire app, buttons, chips and headers, looks festive; afterwards the normal scheme returns with no screen code changed.

kotlin
private val DiwaliColors = lightColorScheme(
    primary = Color(0xFF7B1E3A),
    secondary = Color(0xFFD4A017),
)

@Composable
fun StoreTheme(festive: Boolean, content: @Composable () -> Unit) {
    MaterialTheme(colorScheme = if (festive) DiwaliColors else LightColors, content = content)
}
One switch changes the look of the whole app.

Practice (0/3 done)

Task 1 · Question

Why use MaterialTheme.colorScheme.primary instead of Color(0xFF00695C) in a screen?

Task 2 · Question

From which Android version is dynamic colour available?

Task 3 · Practice

Create a brand theme for a chai shop app: generate light and dark schemes with the Material Theme Builder from one colour, add them to Theme.kt, use dynamic colour on Android 12+ behind a setting, and replace every hard-coded colour in your screens with colorScheme roles. Check the app in dark mode.

Quick quiz

Question 1

1.What does onPrimary mean?

Question 2

2.Which function detects whether the system is in dark mode in Compose?

Question 3

3.Where do text styles like titleLarge come from?

Question 4

4.What is a good reason NOT to use dynamic colour?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What does onPrimary mean?

Answer: The colour for text and icons placed on top of primary

On-colours ensure contrast on their base colour.

Which function detects whether the system is in dark mode in Compose?

Answer: isSystemInDarkTheme()

isSystemInDarkTheme() reads the system setting.

Where do text styles like titleLarge come from?

Answer: MaterialTheme.typography

Use the type scale from the theme.

What is a good reason NOT to use dynamic colour?

Answer: The brand needs fixed, recognisable colours

It is a product decision.

How do you make the app follow the phone's dark mode setting?Related

Answer: themeMode: ThemeMode.system with a darkTheme

Provide darkTheme and use ThemeMode.system.

From Images, icons, fonts and themes

Which font family suits a page with Hindi text?Related

Answer: Noto Sans Devanagari

Devanagari script needs a font that contains its letters.

From Typography: fonts and readable text

How is an AlertDialog shown in Compose?Related

Answer: By including it in the composition while a state flag is true

Declarative: state decides whether it appears.

From Material components

Why use dvh instead of vh for a full-height section on phones?Related

Answer: dvh follows the visible height when the address bar shows or hides

The dynamic viewport unit matches the space actually visible on mobile browsers.

From Colours, backgrounds and units

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 2 more topics in “Permissions, Material 3 and polish” before its exam: Material components, Accessibility and adaptive layouts.
  2. Module 9 exam: Permissions, Material 3 and polish · 13 questions · 25 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, Testing Android apps. 50 topics left in the course before the final exam.

← Previous: Runtime permissions