Expert: features and shipping · Permissions, Material 3 and polish · topic 36 of 50 · 30 min
Material 3 theming
Explanation
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
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,
)
}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
// 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))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.
val colorScheme = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ->
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
darkTheme -> DarkColors
else -> LightColors
}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.
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 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.
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)
}Practice (0/3 done)
Why use MaterialTheme.colorScheme.primary instead of Color(0xFF00695C) in a screen?
From which Android version is dynamic colour available?
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
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Material componentsPermissions, Material 3 and polish · same module
- Accessibility and adaptive layoutsPermissions, Material 3 and polish · same module
- Images, icons, fonts and themesFlutter and Dart · Layouts
- Typography: fonts and readable textFrontend Web Development · CSS basics
- Colours, backgrounds and unitsFrontend Web Development · CSS basics
- How CSS worksFrontend Web Development · CSS basics
Questions people ask about this
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.
Which font family suits a page with Hindi text?Related
Answer: Noto Sans Devanagari
Devanagari script needs a font that contains its letters.
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.
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
- 2 more topics in “Permissions, Material 3 and polish” before its exam: Material components, Accessibility and adaptive layouts.
- Module 9 exam: Permissions, Material 3 and polish · 13 questions · 25 min, without help. 4 topics of this module still to finish first.
- Then the next module, Testing Android apps. 50 topics left in the course before the final exam.