Material Design 3 (M3) is the default design system in Jetpack Compose. Here’s how to set it up and use it.
Basic M3 theme
// ui/theme/Color.kt
val Purple80 = Color(0xFFD0BCFF)
val Purple40 = Color(0xFF6650A4)
val Pink80 = Color(0xFFEFB8C8)
val Pink40 = Color(0xFF7D5260)
// ui/theme/Theme.kt
private val LightColorScheme = lightColorScheme(
primary = Purple40,
onPrimary = Color.White,
primaryContainer = Purple80,
secondary = Pink40,
onSecondary = Color.White,
tertiary = Color(0xFF7D5260),
background = Color(0xFFFFFBFE),
surface = Color(0xFFFFFBFE),
)
private val DarkColorScheme = darkColorScheme(
primary = Purple80,
onPrimary = Color.Black,
primaryContainer = Purple40,
secondary = Pink80,
onSecondary = Color.Black,
tertiary = Pink80,
background = Color(0xFF1C1B1F),
surface = Color(0xFF1C1B1F),
)
@Composable
fun MyTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
dynamicColor: Boolean = true,
content: @Composable () -> Unit,
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context)
else dynamicLightColorScheme(context)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
content = content,
)
}Typography
// ui/theme/Type.kt
val Typography = Typography(
displayLarge = TextStyle(
fontSize = 57.sp,
lineHeight = 64.sp,
fontWeight = FontWeight.Normal,
),
headlineMedium = TextStyle(
fontSize = 28.sp,
lineHeight = 36.sp,
fontWeight = FontWeight.Normal,
),
titleLarge = TextStyle(
fontSize = 22.sp,
lineHeight = 28.sp,
fontWeight = FontWeight.Normal,
),
bodyLarge = TextStyle(
fontSize = 16.sp,
lineHeight = 24.sp,
fontWeight = FontWeight.Normal,
),
bodyMedium = TextStyle(
fontSize = 14.sp,
lineHeight = 20.sp,
fontWeight = FontWeight.Normal,
),
labelSmall = TextStyle(
fontSize = 11.sp,
lineHeight = 16.sp,
fontWeight = FontWeight.Medium,
),
)
// Using typography
Text(
text = "Headline",
style = MaterialTheme.typography.headlineMedium,
)
Text(
text = "Body text",
style = MaterialTheme.typography.bodyLarge,
)Common M3 components
Buttons
// Filled button (primary action)
FilledButton(onClick = { /* ... */ }) {
Text("Save")
}
// Elevated button
ElevatedButton(onClick = { /* ... */ }) {
Text("Edit")
}
// Outlined button
OutlinedButton(onClick = { /* ... */ }) {
Text("Cancel")
}
// Text button
TextButton(onClick = { /* ... */ }) {
Text("Learn more")
}
// Icon button
IconButton(onClick = { /* ... */ }) {
Icon(Icons.Default.Favorite, contentDescription = "Favorite")
}
// FAB
FloatingActionButton(onClick = { /* ... */ }) {
Icon(Icons.Default.Add, contentDescription = "Add")
}
// Extended FAB
ExtendedFloatingActionButton(
onClick = { /* ... */ },
icon = { Icon(Icons.Default.Add, contentDescription = null) },
text = { Text("New item") },
)Cards
// Elevated card
ElevatedCard(
onClick = { /* ... */ },
modifier = Modifier.fillMaxWidth()
) {
Column(modifier = Modifier.padding(16.dp)) {
Text("Card Title", style = MaterialTheme.typography.titleLarge)
Text("Card content goes here", style = MaterialTheme.typography.bodyMedium)
}
}
// Outlined card
OutlinedCard(
onClick = { /* ... */ },
) {
Text("Outlined card content")
}
// Filled card
FilledCard(onClick = { /* ... */ }) {
Text("Filled card content")
}TopAppBar
Scaffold(
topBar = {
TopAppBar(
title = { Text("My App") },
navigationIcon = {
IconButton(onClick = { navController.popBackStack() }) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
}
},
actions = {
IconButton(onClick = { /* search */ }) {
Icon(Icons.Default.Search, contentDescription = "Search")
}
IconButton(onClick = { /* settings */ }) {
Icon(Icons.Default.Settings, contentDescription = "Settings")
}
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.primaryContainer,
titleContentColor = MaterialTheme.colorScheme.onPrimaryContainer,
)
)
}
) { innerPadding ->
// Content
}Dialogs
var showDialog by remember { mutableStateOf(false) }
if (showDialog) {
AlertDialog(
onDismissRequest = { showDialog = false },
title = { Text("Confirm") },
text = { Text("Are you sure you want to delete this item?") },
confirmButton = {
TextButton(onClick = {
// Delete action
showDialog = false
}) { Text("Delete") }
},
dismissButton = {
TextButton(onClick = { showDialog = false }) { Text("Cancel") }
}
)
}Snackbars
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
Scaffold(
snackbarHost = { SnackbarHost(snackbarHostState) }
) { innerPadding ->
Column(modifier = Modifier.padding(innerPadding)) {
Button(onClick = {
scope.launch {
snackbarHostState.showSnackbar("Item deleted", actionLabel = "Undo")
}
}) {
Text("Show Snackbar")
}
}
}