Material 3 provides a rich set of pre-built components. This reference covers every major M3 component with usage examples.
Cards
Cards contain content and actions on a single topic.
// Elevated card (shadow, lifts on hover)
ElevatedCard(
onClick = { /* navigate */ },
modifier = Modifier.fillMaxWidth()
) {
Text("Elevated card content")
}
// Filled card (solid background, no shadow)
FilledCard(
modifier = Modifier.fillMaxWidth()
) {
Text("Filled card content")
}
// Outlined card (border, no shadow)
OutlinedCard(
modifier = Modifier.fillMaxWidth()
) {
Text("Outlined card content")
}
// Card with rich content
ElevatedCard(
modifier = Modifier.fillMaxWidth()
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Card Title",
style = MaterialTheme.typography.titleMedium
)
Spacer(Modifier.height(8.dp))
Text(
text = "Supporting text goes here.",
style = MaterialTheme.typography.bodyMedium
)
Spacer(Modifier.height(12.dp))
Row(horizontalArrangement = Arrangement.End, modifier = Modifier.fillMaxWidth()) {
TextButton(onClick = { /* dismiss */ }) { Text("Dismiss") }
TextButton(onClick = { /* learn more */ }) { Text("Learn More") }
}
}
}Card elevation and interaction
// Clickable card with custom elevation
ElevatedCard(
onClick = { /* handle */ },
elevation = CardDefaults.elevatedCardElevation(
defaultElevation = 2.dp,
pressedElevation = 8.dp,
hoveredElevation = 4.dp,
)
) {
Text("Interactive card")
}Dialogs
AlertDialog
var showDialog by remember { mutableStateOf(false) }
if (showDialog) {
AlertDialog(
onDismissRequest = { showDialog = false },
title = { Text("Confirm delete") },
text = { Text("Are you sure you want to delete this item? This cannot be undone.") },
confirmButton = {
TextButton(onClick = {
// Perform delete
showDialog = false
}) { Text("Delete") }
},
dismissButton = {
TextButton(onClick = { showDialog = false }) { Text("Cancel") }
},
icon = { Icon(Icons.Default.Delete, contentDescription = null) },
)
}
// Trigger
Button(onClick = { showDialog = true }) { Text("Delete item") }DatePicker
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DatePickerExample() {
var showPicker by remember { mutableStateOf(false) }
var selectedDate by remember { mutableStateOf<LocalDate?>(null) }
if (showPicker) {
val state = rememberDatePickerState()
DatePickerDialog(
onDismissRequest = { showPicker = false },
confirmButton = {
TextButton(onClick = {
selectedDate = state.selectedDateMillis?.let {
Instant.fromEpochMilliseconds(it)
.atZone(ZoneId.systemDefault())
.toLocalDate()
}
showPicker = false
}) { Text("OK") }
},
dismissButton = {
TextButton(onClick = { showPicker = false }) { Text("Cancel") }
}
) {
DatePicker(state = state)
}
}
OutlinedTextField(
value = selectedDate?.toString() ?: "",
onValueChange = {},
readOnly = true,
label = { Text("Select date") },
trailingIcon = {
IconButton(onClick = { showPicker = true }) {
Icon(Icons.Default.CalendarMonth, "Pick date")
}
},
modifier = Modifier.fillMaxWidth()
)
}TimePicker
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TimePickerExample() {
var showPicker by remember { mutableStateOf(false) }
val state = rememberTimePickerState()
if (showPicker) {
AlertDialog(
onDismissRequest = { showPicker = false },
confirmButton = {
TextButton(onClick = { showPicker = false }) { Text("OK") }
},
) {
TimePicker(state = state)
}
}
OutlinedTextField(
value = "${state.hour}:${state.minute.toString().padStart(2, '0')}",
onValueChange = {},
readOnly = true,
label = { Text("Select time") },
trailingIcon = {
IconButton(onClick = { showPicker = true }) {
Icon(Icons.Default.Schedule, "Pick time")
}
},
)
}Snackbars
@Composable
fun SnackbarExample() {
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
Scaffold(
snackbarHost = { SnackbarHost(snackbarHostState) }
) { innerPadding ->
Column(
modifier = Modifier.padding(innerPadding).padding(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
// Simple snackbar
Button(onClick = {
scope.launch {
snackbarHostState.showSnackbar("Item deleted")
}
}) { Text("Show Snackbar") }
// Snackbar with action
Button(onClick = {
scope.launch {
val result = snackbarHostState.showSnackbar(
message = "Item archived",
actionLabel = "Undo",
duration = SnackbarDuration.Short,
)
if (result == SnackbarResult.ActionPerformed) {
// Undo the action
}
}
}) { Text("Archive with undo") }
}
}
}Chips
// Filter chip (selectable)
var selected by remember { mutableStateOf(false) }
FilterChip(
selected = selected,
onSelectedChange = { selected = it },
label = { Text("Filter") },
leadingIcon = if (selected) {
{ Icon(Icons.Default.Check, contentDescription = null, modifier = Modifier.size(16.dp)) }
} else null,
)
// Input chip (removable, like a tag)
InputChip(
selected = true,
onClick = { /* toggle */ },
label = { Text("Kotlin") },
trailingIcon = {
Icon(Icons.Default.Close, contentDescription = "Remove", modifier = Modifier.size(16.dp))
},
)
// Suggestion chip (for search suggestions)
SuggestionChip(
onClick = { /* apply suggestion */ },
label = { Text("Elixir") },
icon = { Icon(Icons.Default.Search, contentDescription = null, modifier = Modifier.size(16.dp)) },
)
// Assist chip (action shortcut)
AssistChip(
onClick = { /* perform action */ },
label = { Text("Add event") },
leadingIcon = { Icon(Icons.Default.Add, contentDescription = null, modifier = Modifier.size(16.dp)) },
)Tabs
@Composable
fun TabExample() {
var selectedTab by remember { mutableStateOf(0) }
val tabs = listOf("Home", "Search", "Profile")
Column {
// Fixed tabs (all tabs visible, equal width)
TabRow(selectedTabIndex = selectedTab) {
tabs.forEachIndexed { index, title ->
Tab(
selected = selectedTab == index,
onClick = { selectedTab = index },
text = { Text(title) },
icon = {
when (index) {
0 -> Icon(Icons.Default.Home, contentDescription = null)
1 -> Icon(Icons.Default.Search, contentDescription = null)
2 -> Icon(Icons.Default.Person, contentDescription = null)
}
}
)
}
}
// Tab content
when (selectedTab) {
0 -> HomeTab()
1 -> SearchTab()
2 -> ProfileTab()
}
}
}
// Scrollable tabs (when you have many tabs)
@Composable
fun ScrollableTabExample() {
var selectedTab by remember { mutableStateOf(0) }
val tabs = (0..20).map { "Tab $it" }
ScrollableTabRow(selectedTabIndex = selectedTab) {
tabs.forEachIndexed { index, title ->
Tab(
selected = selectedTab == index,
onClick = { selectedTab = index },
text = { Text(title) }
)
}
}
}
// Secondary tabs (for sub-sections within a page)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SecondaryTabExample() {
var selected by remember { mutableStateOf(0) }
val tabs = listOf("Day", "Week", "Month")
SecondaryTabRow(selectedTabIndex = selected) {
tabs.forEachIndexed { index, title ->
Tab(
selected = selected == index,
onClick = { selected = index },
text = { Text(title) }
)
}
}
}Top App Bars
// Small top app bar (default)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SmallTopBar() {
TopAppBar(
title = { Text("My App") },
navigationIcon = {
IconButton(onClick = { /* back */ }) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, "Back")
}
},
actions = {
IconButton(onClick = { /* search */ }) {
Icon(Icons.Default.Search, "Search")
}
IconButton(onClick = { /* more */ }) {
Icon(Icons.Default.MoreVert, "More")
}
},
)
}
// Center-aligned top app bar
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CenterAlignedTopBar() {
CenterAlignedTopAppBar(
title = { Text("My App") },
navigationIcon = {
IconButton(onClick = { /* menu */ }) {
Icon(Icons.Default.Menu, "Menu")
}
},
actions = {
IconButton(onClick = { /* search */ }) {
Icon(Icons.Default.Search, "Search")
}
},
)
}
// Medium top app bar (title moves up on scroll)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MediumTopBar() {
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
MediumTopAppBar(
title = { Text("Settings") },
scrollBehavior = scrollBehavior,
)
}
// Large top app bar (collapses on scroll)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LargeTopBar() {
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
LargeTopAppBar(
title = { Text("My Journal") },
scrollBehavior = scrollBehavior,
)
}Bottom Navigation
NavigationBar (bottom tabs)
@Composable
fun BottomNavExample() {
var selectedItem by remember { mutableStateOf(0) }
val items = listOf("Home", "Search", "Favorites", "Profile")
Scaffold(
bottomBar = {
NavigationBar {
NavigationBarItem(
selected = selectedItem == 0,
onClick = { selectedItem = 0 },
icon = { Icon(Icons.Default.Home, contentDescription = null) },
label = { Text(items[0]) },
)
NavigationBarItem(
selected = selectedItem == 1,
onClick = { selectedItem = 1 },
icon = { Icon(Icons.Default.Search, contentDescription = null) },
label = { Text(items[1]) },
)
NavigationBarItem(
selected = selectedItem == 2,
onClick = { selectedItem = 2 },
icon = { Icon(Icons.Default.Favorite, contentDescription = null) },
label = { Text(items[2]) },
)
NavigationBarItem(
selected = selectedItem == 3,
onClick = { selectedItem = 3 },
icon = { Icon(Icons.Default.Person, contentDescription = null) },
label = { Text(items[3]) },
)
}
}
) { innerPadding ->
ContentScreen(modifier = Modifier.padding(innerPadding), selectedTab = selectedItem)
}
}NavigationRail (side tabs, for tablets/landscape)
@Composable
fun NavigationRailExample() {
var selectedItem by remember { mutableStateOf(0) }
Row {
NavigationRail {
NavigationRailItem(
selected = selectedItem == 0,
onClick = { selectedItem = 0 },
icon = { Icon(Icons.Default.Home, contentDescription = null) },
label = { Text("Home") },
)
NavigationRailItem(
selected = selectedItem == 1,
onClick = { selectedItem = 1 },
icon = { Icon(Icons.Default.Search, contentDescription = null) },
label = { Text("Search") },
)
NavigationRailItem(
selected = selectedItem == 2,
onClick = { selectedItem = 2 },
icon = { Icon(Icons.Default.Favorite, contentDescription = null) },
label = { Text("Favorites") },
)
}
ContentScreen(selectedTab = selectedItem)
}
}NavigationDrawer (side menu)
// Modal drawer (opens on top of content)
@Composable
fun ModalDrawerExample() {
val drawerState = rememberDrawerState(DrawerValue.Closed)
val scope = rememberCoroutineScope()
ModalNavigationDrawer(
drawerContent = {
ModalDrawerSheet {
Spacer(Modifier.height(12.dp))
Text("Menu", modifier = Modifier.padding(16.dp), style = MaterialTheme.typography.titleMedium)
HorizontalDivider()
NavigationDrawerItem(
label = { Text("Home") },
selected = true,
onClick = { scope.launch { drawerState.close() } },
icon = { Icon(Icons.Default.Home, contentDescription = null) },
)
NavigationDrawerItem(
label = { Text("Settings") },
selected = false,
onClick = { scope.launch { drawerState.close() } },
icon = { Icon(Icons.Default.Settings, contentDescription = null) },
)
}
},
drawerState = drawerState
) {
Scaffold(
topBar = {
TopAppBar(
title = { Text("App") },
navigationIcon = {
IconButton(onClick = { scope.launch { drawerState.open() } }) {
Icon(Icons.Default.Menu, "Menu")
}
}
)
}
) { innerPadding ->
Content(modifier = Modifier.padding(innerPadding))
}
}
}
// Permanent drawer (always visible on large screens)
@Composable
fun PermanentDrawerExample() {
PermanentNavigationDrawer(
drawerContent = {
PermanentDrawerSheet {
Text("App", modifier = Modifier.padding(16.dp), style = MaterialTheme.typography.titleLarge)
NavigationDrawerItem(
label = { Text("Inbox") },
selected = true,
onClick = { /* ... */ },
icon = { Icon(Icons.Default.Inbox, contentDescription = null) },
badge = { Text("12") },
)
NavigationDrawerItem(
label = { Text("Sent") },
selected = false,
onClick = { /* ... */ },
icon = { Icon(Icons.Default.Send, contentDescription = null) },
)
}
}
) {
Content()
}
}Floating Action Buttons
// Standard FAB
FloatingActionButton(
onClick = { /* add */ },
) {
Icon(Icons.Default.Add, contentDescription = "Add")
}
// Small FAB
SmallFloatingActionButton(
onClick = { /* add */ },
) {
Icon(Icons.Default.Add, contentDescription = "Add")
}
// Large FAB
LargeFloatingActionButton(
onClick = { /* add */ },
) {
Icon(Icons.Default.Add, contentDescription = "Add")
}
// Extended FAB (with text)
ExtendedFloatingActionButton(
onClick = { /* compose */ },
icon = { Icon(Icons.Default.Edit, contentDescription = null) },
text = { Text("Compose") },
)
// Extended FAB that collapses to icon
var expanded by remember { mutableStateOf(true) }
ExtendedFloatingActionButton(
onClick = { /* ... */ },
expanded = expanded,
icon = { Icon(Icons.Default.Edit, contentDescription = null) },
text = { Text("Compose") },
)Bottom Sheets
// Modal bottom sheet
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ModalBottomSheetExample() {
var showSheet by remember { mutableStateOf(false) }
if (showSheet) {
ModalBottomSheet(
onDismissRequest = { showSheet = false },
) {
Column(modifier = Modifier.padding(16.dp)) {
Text("Sheet Title", style = MaterialTheme.typography.titleLarge)
Spacer(Modifier.height(8.dp))
Text("Sheet content goes here.")
Spacer(Modifier.height(24.dp))
}
}
}
Button(onClick = { showSheet = true }) { Text("Show sheet") }
}
// Standard bottom sheet (part of Scaffold)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun StandardBottomSheetExample() {
val sheetState = rememberStandardBottomSheetState(
initialValue = SheetValue.PartiallyExpanded,
skipHiddenState = false,
)
val scaffoldState = rememberBottomSheetScaffoldState(bottomSheetState = sheetState)
BottomSheetScaffold(
sheetContent = {
Column(modifier = Modifier.padding(16.dp)) {
Text("Bottom sheet content", style = MaterialTheme.typography.titleMedium)
}
},
scaffoldState = scaffoldState,
sheetPeekHeight = 56.dp,
) { innerPadding ->
Content(modifier = Modifier.padding(innerPadding))
}
}Dropdown Menus
@Composable
fun DropdownMenuExample() {
var expanded by remember { mutableStateOf(false) }
var selectedOption by remember { mutableStateOf("Select") }
Box {
OutlinedTextField(
value = selectedOption,
onValueChange = {},
readOnly = true,
label = { Text("Option") },
trailingIcon = { Icon(Icons.Default.ArrowDropDown, null) },
modifier = Modifier
.fillMaxWidth()
.menuAnchor()
.clickable { expanded = true }
)
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false }
) {
DropdownMenuItem(
text = { Text("Option 1") },
onClick = {
selectedOption = "Option 1"
expanded = false
}
)
DropdownMenuItem(
text = { Text("Option 2") },
onClick = {
selectedOption = "Option 2"
expanded = false
}
)
Divider()
DropdownMenuItem(
text = { Text("Option 3") },
onClick = {
selectedOption = "Option 3"
expanded = false
}
)
}
}
}
// Icon button context menu
@Composable
fun OverflowMenu() {
var expanded by remember { mutableStateOf(false) }
Box {
IconButton(onClick = { expanded = true }) {
Icon(Icons.Default.MoreVert, "More")
}
DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
DropdownMenuItem(
text = { Text("Settings") },
onClick = { /* ... */ },
leadingIcon = { Icon(Icons.Default.Settings, null) }
)
DropdownMenuItem(
text = { Text("Help") },
onClick = { /* ... */ },
leadingIcon = { Icon(Icons.Default.Help, null) }
)
}
}
}Toggle Buttons
// Segmented button (exclusive selection)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SegmentedButtonExample() {
var selected by remember { mutableStateOf(0) }
val options = listOf("Day", "Week", "Month")
SingleChoiceSegmentedButtonRow {
options.forEachIndexed { index, label ->
SegmentedButton(
selected = index == selected,
onClick = { selected = index },
shape = SegmentedButtonShape(index, options.size),
) {
Text(label)
}
}
}
}
// Icon toggle button
var bookmarked by remember { mutableStateOf(false) }
IconToggleButton(checked = bookmarked, onCheckedChange = { bookmarked = it }) {
Icon(
if (bookmarked) Icons.Default.Favorite else Icons.Default.FavoriteBorder,
contentDescription = "Favorite",
tint = if (bookmarked) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
)
}Slider and Range Slider
// Continuous slider
var value by remember { mutableStateOf(0.5f) }
Slider(
value = value,
onValueChange = { value = it },
valueRange = 0f..1f,
steps = 4, // 5 stops: 0.0, 0.25, 0.5, 0.75, 1.0
)
// Discrete slider with steps
var stepValue by remember { mutableStateOf(0f) }
Slider(
value = stepValue,
onValueChange = { stepValue = it },
valueRange = 0f..100f,
steps = 9, // 10 stops
)
// Range slider
var range by remember { mutableStateOf(25f..75f) }
RangeSlider(
value = range,
onValueChange = { range = it },
valueRange = 0f..100f,
)Badges
// Badge on icon
BadgedBox(
badge = {
Badge { Text("3") }
}
) {
Icon(Icons.Default.Mail, contentDescription = "Mail")
}
// Dot badge (no number)
BadgedBox(
badge = { Badge }
) {
Icon(Icons.Default.Notifications, contentDescription = "Notifications")
}
// Badge on navigation item
NavigationBarItem(
selected = false,
onClick = { /* ... */ },
icon = {
BadgedBox(badge = { Badge { Text("5") } }) {
Icon(Icons.Default.Mail, contentDescription = null)
}
},
label = { Text("Inbox") },
)Tooltip
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TooltipExample() {
// Plain tooltip
Box {
val tooltipState = rememberTooltipState()
TooltipBox(
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
tooltip = { PlainTooltip { Text("Add new item") } },
state = tooltipState,
) {
IconButton(onClick = { /* add */ }) {
Icon(Icons.Default.Add, contentDescription = "Add")
}
}
}
// Rich tooltip (with subtitle and action)
Box {
val richState = rememberTooltipState()
TooltipBox(
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
tooltip = {
RichTooltip(
title = { Text("Format") },
action = {
TextButton(onClick = { /* learn more */ }) { Text("Learn more") }
}
) {
Text("Bold, italic, and underline formatting options.")
}
},
state = richState,
) {
IconButton(onClick = { /* format */ }) {
Icon(Icons.Default.FormatBold, contentDescription = "Format")
}
}
}
}Divider
// Horizontal divider
HorizontalDivider()
// With thickness and color
HorizontalDivider(
thickness = 2.dp,
color = MaterialTheme.colorScheme.outlineVariant,
)
// Vertical divider
VerticalDivider(modifier = Modifier.height(24.dp))
// Divider with text
Row(verticalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth()) {
HorizontalDivider(modifier = Modifier.weight(1f))
Text(" OR ", style = MaterialTheme.typography.labelSmall)
HorizontalDivider(modifier = Modifier.weight(1f))
}SwipeToDismiss
@Composable
fun SwipeToDismissList(items: List<String>, onDismiss: (String) -> Unit) {
LazyColumn {
items(items, key = { it }) { item ->
val state = rememberSwipeToDismissBoxState(
confirmValueChange = { value ->
if (value == SwipeToDismissBoxValue.EndToStart) {
onDismiss(item)
true
} else false
},
positionalThreshold = { totalDistance -> totalDistance * 0.5f },
)
SwipeToDismissBox(
state = state,
backgroundContent = {
val color = when {
state.progress > 0 -> MaterialTheme.colorScheme.errorContainer
else -> Color.Transparent
}
Box(
modifier = Modifier
.fillMaxSize()
.background(color)
.padding(horizontal = 20.dp),
contentAlignment = Alignment.CenterEnd,
) {
Icon(Icons.Default.Delete, "Delete", tint = MaterialTheme.colorScheme.onErrorContainer)
}
},
enableDismissFromStartToEnd = false,
) {
Card(modifier = Modifier.fillMaxWidth()) {
Text(item, modifier = Modifier.padding(16.dp))
}
}
}
}
}PullToRefresh
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PullToRefreshExample(viewModel: MyViewModel) {
val isRefreshing by viewModel.isRefreshing.collectAsStateWithLifecycle()
PullToRefreshBox(
isRefreshing = isRefreshing,
onRefresh = { viewModel.refresh() },
) {
LazyColumn {
items(viewModel.items) { item ->
ItemRow(item)
}
}
}
}Full Scaffold example
Putting it all together — a complete screen with top bar, bottom navigation, FAB, and snackbar:
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CompleteScreen() {
var selectedTab by remember { mutableStateOf(0) }
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
val drawerState = rememberDrawerState(DrawerValue.Closed)
ModalNavigationDrawer(
drawerContent = {
ModalDrawerSheet {
Text("Menu", modifier = Modifier.padding(16.dp), style = MaterialTheme.typography.titleMedium)
HorizontalDivider()
NavigationDrawerItem(
label = { Text("Home") },
selected = selectedTab == 0,
onClick = { selectedTab = 0; scope.launch { drawerState.close() } },
icon = { Icon(Icons.Default.Home, null) },
)
NavigationDrawerItem(
label = { Text("Settings") },
selected = false,
onClick = { scope.launch { drawerState.close() } },
icon = { Icon(Icons.Default.Settings, null) },
)
}
},
drawerState = drawerState,
) {
Scaffold(
topBar = {
TopAppBar(
title = { Text("My App") },
navigationIcon = {
IconButton(onClick = { scope.launch { drawerState.open() } }) {
Icon(Icons.Default.Menu, "Menu")
}
},
actions = {
IconButton(onClick = { /* search */ }) {
Icon(Icons.Default.Search, "Search")
}
},
)
},
bottomBar = {
NavigationBar {
NavigationBarItem(selected = selectedTab == 0, onClick = { selectedTab = 0 },
icon = { Icon(Icons.Default.Home, null) }, label = { Text("Home") })
NavigationBarItem(selected = selectedTab == 1, onClick = { selectedTab = 1 },
icon = { Icon(Icons.Default.Search, null) }, label = { Text("Search") })
NavigationBarItem(selected = selectedTab == 2, onClick = { selectedTab = 2 },
icon = { Icon(Icons.Default.Person, null) }, label = { Text("Profile") })
}
},
floatingActionButton = {
FloatingActionButton(onClick = {
scope.launch {
snackbarHostState.showSnackbar("Item added")
}
}) {
Icon(Icons.Default.Add, "Add")
}
},
snackbarHost = { SnackbarHost(snackbarHostState) },
) { innerPadding ->
when (selectedTab) {
0 -> HomeTab(modifier = Modifier.padding(innerPadding))
1 -> SearchTab(modifier = Modifier.padding(innerPadding))
2 -> ProfileTab(modifier = Modifier.padding(innerPadding))
}
}
}
}Component quick reference
| Component | Use for |
|---|---|
Card / ElevatedCard / OutlinedCard |
Grouped content with actions |
AlertDialog |
Confirmation, alerts, choices |
DatePicker / TimePicker |
Date and time selection |
Snackbar / SnackbarHost |
Brief messages with optional action |
FilterChip / InputChip / SuggestionChip / AssistChip |
Tags, filters, suggestions |
TabRow / ScrollableTabRow / SecondaryTabRow |
Tab navigation |
TopAppBar / CenterAlignedTopAppBar / MediumTopAppBar / LargeTopAppBar |
Screen headers |
NavigationBar / NavigationRail / NavigationDrawer |
App-level navigation |
FloatingActionButton / ExtendedFloatingActionButton |
Primary action |
ModalBottomSheet / BottomSheetScaffold |
Bottom-anchored panels |
DropdownMenu |
Context menus, overflow menus |
SegmentedButton |
Mutually exclusive options |
IconToggleButton |
Toggle icons (favorite, bookmark) |
Slider / RangeSlider |
Continuous value selection |
Badge / BadgedBox |
Notification counts, status dots |
Tooltip / PlainTooltip / RichTooltip |
Descriptive hover text |
HorizontalDivider / VerticalDivider |
Visual separators |
SwipeToDismissBox |
Swipe-to-delete list items |
PullToRefreshBox |
Pull-to-refresh gesture |
Scaffold |
Full screen layout (top bar, bottom bar, FAB, snackbar) |