Android Material Design 3 Implementation Guide

Material Design 3, also known as Material You, represents the biggest visual overhaul of Android’s design language since Material Design was introduced in 2014. Launched with Android 12, Material Design 3 brings dynamic colour, updated components, and a more personal, expressive design system.

For Android developers in 2022, adopting Material Design 3 means your app feels current, native, and aligned with the direction Google is taking the platform. This guide walks through the practical implementation.

What Changed in Material Design 3

What Changed in Material Design 3 Infographic

Dynamic Colour

The headline feature. On Android 12 and above, Material Design 3 can extract colours from the user’s wallpaper and apply them throughout your app. Every user’s instance of your app looks slightly different, matching their personal aesthetic.

Updated Colour System

Material Design 3 replaces the old primary/secondary colour system with a more nuanced scheme:

  • Primary, Secondary, Tertiary: Three accent colour groups instead of two
  • Surface colours: Multiple elevation-based surface tones
  • On-colours: Dedicated colours for text and icons on each background
  • Container colours: Specific colours for component containers (buttons, cards, chips)

Updated Components

Many Material components have been redesigned:

  • New button styles (filled, outlined, text, elevated, tonal)
  • Redesigned navigation bar (replaces bottom navigation)
  • Updated cards, chips, and dialogs
  • New top app bar variants

Updated Typography

The type scale has been simplified to five categories with three sizes each:

  • Display (large, medium, small)
  • Headline (large, medium, small)
  • Title (large, medium, small)
  • Body (large, medium, small)
  • Label (large, medium, small

Setup Infographic )

Setup

Dependencies

Add the Material Design 3 library:

// build.gradle (app)
dependencies {
    // For View-based UI
    implementation 'com.google.android.material:material:1.6.0'

    // For Jetpack Compose
    implementation 'androidx.compose.material3:material3:1.0.0-alpha11'
}

Theme Configuration (View System)

Create your Material Design 3 theme:

{/* res/values/themes.xml */}
<style name="Theme.MyApp" parent="Theme.Material3.DayNight.NoActionBar">
    {/* Primary */}
    <item name="colorPrimary">@color/md_theme_primary</item>
    <item name="colorOnPrimary">@color/md_theme_onPrimary</item>
    <item name="colorPrimaryContainer">@color/md_theme_primaryContainer</item>
    <item name="colorOnPrimaryContainer">@color/md_theme_onPrimaryContainer</item>

    {/* Secondary */}
    <item name="colorSecondary">@color/md_theme_secondary</item>
    <item name="colorOnSecondary">@color/md_theme_onSecondary</item>
    <item name="colorSecondaryContainer">@color/md_theme_secondaryContainer</item>
    <item name="colorOnSecondaryContainer">@color/md_theme_onSecondaryContainer</item>

    {/* Tertiary */}
    <item name="colorTertiary">@color/md_theme_tertiary</item>
    <item name="colorOnTertiary">@color/md_theme_onTertiary</item>
    <item name="colorTertiaryContainer">@color/md_theme_tertiaryContainer</item>
    <item name="colorOnTertiaryContainer">@color/md_theme_onTertiaryContainer</item>

    {/* Background and Surface */}
    <item name="android:colorBackground">@color/md_theme_background</item>
    <item name="colorOnBackground">@color/md_theme_onBackground</item>
    <item name="colorSurface">@color/md_theme_surface</item>
    <item name="colorOnSurface">@color/md_theme_onSurface</item>

    {/* Error */}
    <item name="colorError">@color/md_theme_error</item>
    <item name="colorOnError">@color/md_theme_onError</item>
</style>

Use the Material Theme Builder

Google provides the Material Theme Builder tool (material-foundation.github.io) that generates complete colour schemes from a single seed colour. Export the generated colours directly into your Android project.

Jetpack Compose Theme

@Composable
fun MyAppTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    dynamicColour: Boolean = true,
    content: @Composable () -> Unit
) {
    val colourScheme = when {
        dynamicColour && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
            val context = LocalContext.current
            if (darkTheme) dynamicDarkColorScheme(context)
            else dynamicLightColorScheme(context)
        }
        darkTheme -> darkColorScheme(
            primary = Purple80,
            onPrimary = Purple20,
            primaryContainer = Purple30,
            onPrimaryContainer = Purple90,
            secondary = Green80,
            onSecondary = Green20,
            // ... complete scheme
        )
        else -> lightColorScheme(
            primary = Purple40,
            onPrimary = Color.White,
            primaryContainer = Purple90,
            onPrimaryContainer = Purple10,
            secondary = Green40,
            onSecondary = Color.White,
            // ... complete scheme
        )
    }

    MaterialTheme(
        colorScheme = colourScheme,
        typography = AppTypography,
        content = content
    )
}

Dynamic Colour

Dyna

mic colour works on Android 12 and above. On older devices, fall back to your custom colour scheme:

val useDynamicColour = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S

val colourScheme = if (useDynamicColour) {
    val context = LocalContext.current
    if (isSystemInDarkTheme()) {
        dynamicDarkColorScheme(context)
    } else {
        dynamicLightColorScheme(context)
    }
} else {
    // Your custom colour scheme for older devices
    if (isSystemInDarkTheme()) DarkColourScheme else LightColourScheme
}

Using Theme Colours

Always reference theme colours rather than hardcoding values:

// Compose
@Composable
fun ProfileCard() {
    Card(
        colors = CardDefaults.cardColors(
            containerColor = MaterialTheme.colorScheme.surfaceVariant,
        )
    ) {
        Text(
            text = "User Name",
            style = MaterialTheme.typography.titleMedium,
            color = MaterialTheme.colorScheme.onSurfaceVariant,
        )
    }
}

// XML
<com.google.android.material.card.MaterialCardView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardBackgroundColor="?attr/colorSurfaceVariant">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="?attr/colorOnSurfaceVariant"
        android:textAppearance="?attr/textAppearanceTitleMedium" />
</com.google.android.material.card.MaterialCardView>

Updated

Components

Buttons

Material Design 3 introduces five button types with clear hierarchy:

@Composable
fun ButtonShowcase() {
    Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
        // Highest emphasis
        Button(onClick = { }) {
            Text("Filled Button")
        }

        // Medium-high emphasis
        FilledTonalButton(onClick = { }) {
            Text("Tonal Button")
        }

        // Medium emphasis
        ElevatedButton(onClick = { }) {
            Text("Elevated Button")
        }

        // Medium-low emphasis
        OutlinedButton(onClick = { }) {
            Text("Outlined Button")
        }

        // Lowest emphasis
        TextButton(onClick = { }) {
            Text("Text Button")
        }
    }
}

The new Navigation Bar replaces Bottom Navigation:

@Composable
fun AppNavigationBar(
    selectedTab: Int,
    onTabSelected: (Int) -> Unit
) {
    NavigationBar {
        NavigationBarItem(
            selected = selectedTab == 0,
            onClick = { onTabSelected(0) },
            icon = {
                Icon(Icons.Default.Home, contentDescription = "Home")
            },
            label = { Text("Home") }
        )
        NavigationBarItem(
            selected = selectedTab == 1,
            onClick = { onTabSelected(1) },
            icon = {
                Icon(Icons.Default.Search, contentDescription = "Search")
            },
            label = { Text("Search") }
        )
        NavigationBarItem(
            selected = selectedTab == 2,
            onClick = { onTabSelected(2) },
            icon = {
                Icon(Icons.Default.Person, contentDescription = "Profile")
            },
            label = { Text("Profile") }
        )
    }
}

Top App Bar

Material Design 3 top app bars have new scroll behaviours:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainScreen() {
    val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()

    Scaffold(
        topBar = {
            TopAppBar(
                title = { Text("My App") },
                navigationIcon = {
                    IconButton(onClick = { }) {
                        Icon(Icons.Default.Menu, "Menu")
                    }
                },
                actions = {
                    IconButton(onClick = { }) {
                        Icon(Icons.Default.Search, "Search")
                    }
                },
                scrollBehavior = scrollBehavior,
            )
        },
        modifier = Modifier.nestedScroll(
            scrollBehavior.nestedScrollConnection
        ),
    ) { padding ->
        LazyColumn(contentPadding = padding) {
            // Content
        }
    }
}

Cards

Material Design 3 offers three card variants:

@Composable
fun CardVariants() {
    Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
        // Filled card (default)
        Card(
            colors = CardDefaults.cardColors(
                containerColor = MaterialTheme.colorScheme.surfaceVariant,
            )
        ) {
            CardContent()
        }

        // Elevated card
        ElevatedCard {
            CardContent()
        }

        // Outlined card
        OutlinedCard {
            CardContent()
        }
    }
}

Typography

Define Your Type Scale

val AppTypography = Typography(
    displayLarge = TextStyle(
        fontFamily = FontFamily.Default,
        fontWeight = FontWeight.Normal,
        fontSize = 57.sp,
        lineHeight = 64.sp,
        letterSpacing = (-0.25).sp,
    ),
    headlineMedium = TextStyle(
        fontFamily = FontFamily.Default,
        fontWeight = FontWeight.Normal,
        fontSize = 28.sp,
        lineHeight = 36.sp,
    ),
    titleLarge = TextStyle(
        fontFamily = FontFamily.Default,
        fontWeight = FontWeight.Normal,
        fontSize = 22.sp,
        lineHeight = 28.sp,
    ),
    bodyLarge = TextStyle(
        fontFamily = FontFamily.Default,
        fontWeight = FontWeight.Normal,
        fontSize = 16.sp,
        lineHeight = 24.sp,
        letterSpacing = 0.5.sp,
    ),
    bodyMedium = TextStyle(
        fontFamily = FontFamily.Default,
        fontWeight = FontWeight.Normal,
        fontSize = 14.sp,
        lineHeight = 20.sp,
        letterSpacing = 0.25.sp,
    ),
    labelSmall = TextStyle(
        fontFamily = FontFamily.Default,
        fontWeight = FontWeight.Medium,
        fontSize = 11.sp,
        lineHeight = 16.sp,
        letterSpacing = 0.5.sp,
    ),
)

Using Typography

Text(
    text = "Page Title",
    style = MaterialTheme.typography.headlineMedium,
)

Text(
    text = "Body content goes here",
    style = MaterialTheme.typography.bodyLarge,
)

Text(
    text = "LABEL",
    style = MaterialTheme.typography.labelSmall,
)

Migration from Material Design 2

Colour Mapping

Material Design 2Material Design 3
colorPrimarycolorPrimary
colorPrimaryVariantcolorPrimaryContainer
colorSecondarycolorSecondary
colorSecondaryVariantcolorTertiaryContainer
colorSurfacecolorSurface
colorBackgroundcolorBackground (now android:colorBackground)

Component Migration

MD2 ComponentMD3 Replacement
BottomNavigationNavigationBar
BottomNavigationItemNavigationBarItem
FloatingActionButtonFloatingActionButton (restyled)
TopAppBarTopAppBar, MediumTopAppBar, LargeTopAppBar
CardCard, ElevatedCard, OutlinedCard

Gradual Migration Strategy

You do not need to migrate everything at once. Material Design 3 components coexist with Material Design 2 components:

  1. Update your theme to Material Design 3
  2. Migrate global components first (app bars, navigation, FAB)
  3. Migrate screen-level components progressively
  4. Update individual UI elements last

Conclusion

Material Design 3 is a meaningful upgrade that makes your Android app feel native to the modern Android experience. Dynamic colour personalises every user’s experience, the updated components look contemporary, and the refined colour system gives you more design flexibility.

Start with the theme and dynamic colour support, then progressively update components. The Material Theme Builder tool makes generating a complete colour scheme straightforward, and the Compose integration is particularly clean.

For help implementing Material Design 3 in your Android app, contact eawesome. We build beautiful, modern Android applications for Australian businesses.