An AI reference of Material Design 3 Expressive components available in Jetpack Compose.
Note: Components marked with π have expressive features like shape morphing or enhanced motion.
- Action Components
- Navigation Components
- Containment Components
- Selection Components
- Text Input Components
- Date & Time Components
- Progress & Loading Components
- Communication Components
- Other Components
The standard filled button with optional expressive shape morphing.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ExpressiveButton() {
Button(
onClick = { /* action */ },
shapes = ButtonDefaults.shapes() // Enables shape morphing
) {
Text("Click Me")
}
}Parameters:
onClick: Lambda called when button is clickedmodifier: Modifier for the buttonenabled: Whether the button is enabledshapes: π Shape configuration for morphing animationscolors: Button colorselevation: Button elevationborder: Optional border strokecontentPadding: Padding for button contentinteractionSource: Interaction source for handling interactions
Button with elevation and optional shape morphing.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ExpressiveElevatedButton() {
ElevatedButton(
onClick = { /* action */ },
shapes = ButtonDefaults.shapes()
) {
Text("Elevated")
}
}Button with outline border and optional shape morphing.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ExpressiveOutlinedButton() {
OutlinedButton(
onClick = { /* action */ },
shapes = ButtonDefaults.shapes()
) {
Text("Outlined")
}
}Low-emphasis button with optional shape morphing.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ExpressiveTextButton() {
TextButton(
onClick = { /* action */ },
shapes = ButtonDefaults.shapes()
) {
Text("Text Button")
}
}Standard FAB for primary actions.
FloatingActionButton(onClick = { /* action */ }) {
Icon(Icons.Default.Add, contentDescription = "Add")
}Medium-sized FAB for expressive layouts.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun MediumFAB() {
MediumFloatingActionButton(onClick = { /* action */ }) {
Icon(Icons.Default.Edit, contentDescription = "Edit")
}
}Large FAB for prominent primary actions.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun LargeFAB() {
LargeFloatingActionButton(onClick = { /* action */ }) {
Icon(
Icons.Default.Add,
contentDescription = "Add",
modifier = Modifier.size(36.dp)
)
}
}FAB with extended width for text + icon.
ExtendedFloatingActionButton(
onClick = { /* action */ },
icon = { Icon(Icons.Default.Add, contentDescription = null) },
text = { Text("Create") }
)@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun MediumExtendedFAB() {
MediumExtendedFloatingActionButton(
onClick = { /* action */ },
icon = { Icon(Icons.Default.Edit, contentDescription = null) },
text = { Text("Edit") }
)
}@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun LargeExtendedFAB() {
LargeExtendedFloatingActionButton(
onClick = { /* action */ },
icon = { Icon(Icons.Default.Add, contentDescription = null) },
text = { Text("Create New") }
)
}Standard icon button with optional shape morphing.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ExpressiveIconButton() {
IconButton(
onClick = { /* action */ },
shapes = IconButtonDefaults.shapes()
) {
Icon(Icons.Default.Favorite, contentDescription = "Favorite")
}
}@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ExpressiveFilledTonalIconButton() {
FilledTonalIconButton(
onClick = { /* action */ },
shapes = IconButtonDefaults.shapes()
) {
Icon(Icons.Default.Star, contentDescription = "Star")
}
}@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ExpressiveOutlinedIconButton() {
OutlinedIconButton(
onClick = { /* action */ },
shapes = IconButtonDefaults.shapes()
) {
Icon(Icons.Default.Share, contentDescription = "Share")
}
}Toggle button with shape morphing between checked/unchecked states.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ExpressiveToggleButton() {
var checked by remember { mutableStateOf(false) }
ToggleButton(
checked = checked,
onCheckedChange = { checked = it },
shapes = ToggleButtonDefaults.shapes()
) {
Icon(
if (checked) Icons.Filled.Favorite else Icons.Outlined.FavoriteBorder,
contentDescription = null
)
Spacer(Modifier.size(ToggleButtonDefaults.IconSpacing))
Text("Like")
}
}Parameters:
checked: Whether the button is checkedonCheckedChange: Lambda called on state changeshapes: π Shape configuration for morphing between statescolors: Button colors for different states
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ExpressiveElevatedToggleButton() {
var checked by remember { mutableStateOf(false) }
ElevatedToggleButton(
checked = checked,
onCheckedChange = { checked = it }
) {
Text(if (checked) "Selected" else "Select")
}
}@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ExpressiveOutlinedToggleButton() {
var checked by remember { mutableStateOf(false) }
OutlinedToggleButton(
checked = checked,
onCheckedChange = { checked = it }
) {
Text(if (checked) "On" else "Off")
}
}@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ExpressiveIconToggleButton() {
var checked by remember { mutableStateOf(false) }
IconToggleButton(
checked = checked,
onCheckedChange = { checked = it },
shapes = IconButtonDefaults.shapes()
) {
Icon(
if (checked) Icons.Filled.Bookmark else Icons.Outlined.BookmarkBorder,
contentDescription = "Bookmark"
)
}
}@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ExpressiveFilledTonalIconToggleButton() {
var checked by remember { mutableStateOf(false) }
FilledTonalIconToggleButton(
checked = checked,
onCheckedChange = { checked = it },
shapes = IconButtonDefaults.shapes()
) {
Icon(
if (checked) Icons.Filled.Star else Icons.Outlined.StarBorder,
contentDescription = "Star"
)
}
}@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ExpressiveOutlinedIconToggleButton() {
var checked by remember { mutableStateOf(false) }
OutlinedIconToggleButton(
checked = checked,
onCheckedChange = { checked = it },
shapes = IconButtonDefaults.shapes()
) {
Icon(
if (checked) Icons.Filled.Favorite else Icons.Outlined.FavoriteBorder,
contentDescription = "Favorite"
)
}
}A button split into a main action and a secondary dropdown action.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun SplitButtonExample() {
var expanded by remember { mutableStateOf(false) }
SplitButton(
leadingButton = {
SplitButtonDefaults.LeadingButton(
onClick = { /* Main action */ }
) {
Icon(Icons.Default.Add, contentDescription = null)
Spacer(Modifier.width(8.dp))
Text("Add")
}
},
trailingButton = {
SplitButtonDefaults.TrailingButton(
onClick = { expanded = !expanded },
checked = expanded
)
}
)
}Standard top app bar with optional subtitle support.
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ExpressiveTopAppBar() {
TopAppBar(
title = { Text("Title") },
subtitle = { Text("Subtitle") }, // π Expressive feature
navigationIcon = {
IconButton(onClick = { /* back */ }) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
}
}
)
}Medium-sized top app bar with collapsing behavior.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MediumAppBar() {
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
MediumTopAppBar(
title = { Text("Medium Title") },
scrollBehavior = scrollBehavior
)
}Large top app bar for prominent titles.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LargeAppBar() {
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
LargeTopAppBar(
title = { Text("Large Title") },
scrollBehavior = scrollBehavior
)
}Medium app bar with flexible content and subtitle.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun MediumFlexibleAppBar() {
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
MediumFlexibleTopAppBar(
title = { Text("Flexible Medium") },
subtitle = { Text("With subtitle") },
scrollBehavior = scrollBehavior
)
}Large app bar with flexible content and subtitle.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun LargeFlexibleAppBar() {
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
LargeFlexibleTopAppBar(
title = { Text("Flexible Large") },
subtitle = { Text("Descriptive subtitle") },
titleHorizontalAlignment = Alignment.Start,
scrollBehavior = scrollBehavior
)
}Top app bar with centered title.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CenteredAppBar() {
CenterAlignedTopAppBar(
title = { Text("Centered Title") }
)
}Bottom app bar with optional FAB cutout.
@Composable
fun BottomBar() {
BottomAppBar(
actions = {
IconButton(onClick = { /* action */ }) {
Icon(Icons.Default.Menu, contentDescription = "Menu")
}
},
floatingActionButton = {
FloatingActionButton(onClick = { /* action */ }) {
Icon(Icons.Default.Add, contentDescription = "Add")
}
}
)
}Expressive bottom app bar with flexible arrangements.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun FlexibleBottomBar() {
FlexibleBottomAppBar(
horizontalArrangement = Arrangement.SpaceEvenly,
content = {
IconButton(onClick = { }) { Icon(Icons.Default.Home, null) }
IconButton(onClick = { }) { Icon(Icons.Default.Search, null) }
IconButton(onClick = { }) { Icon(Icons.Default.Settings, null) }
}
)
}Bottom navigation bar for primary destinations.
@Composable
fun BottomNavigation() {
var selectedItem by remember { mutableIntStateOf(0) }
val items = listOf("Home", "Search", "Profile")
NavigationBar {
items.forEachIndexed { index, item ->
NavigationBarItem(
icon = { Icon(Icons.Default.Home, contentDescription = item) },
label = { Text(item) },
selected = selectedItem == index,
onClick = { selectedItem = index }
)
}
}
}Compact navigation bar for limited space.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ShortNavBar() {
var selectedItem by remember { mutableIntStateOf(0) }
ShortNavigationBar(
arrangement = ShortNavigationBarArrangement.EqualWeight
) {
ShortNavigationBarItem(
selected = selectedItem == 0,
onClick = { selectedItem = 0 },
icon = { Icon(Icons.Default.Home, null) },
label = { Text("Home") }
)
ShortNavigationBarItem(
selected = selectedItem == 1,
onClick = { selectedItem = 1 },
icon = { Icon(Icons.Default.Search, null) },
label = { Text("Search") }
)
}
}Modal drawer that slides in from the edge.
@Composable
fun ModalDrawer() {
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
ModalNavigationDrawer(
drawerState = drawerState,
drawerContent = {
ModalDrawerSheet {
NavigationDrawerItem(
label = { Text("Home") },
selected = true,
onClick = { }
)
}
}
) {
// Main content
}
}Drawer that can be dismissed with gesture.
@Composable
fun DismissibleDrawer() {
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
DismissibleNavigationDrawer(
drawerState = drawerState,
drawerContent = {
DismissibleDrawerSheet {
NavigationDrawerItem(
label = { Text("Settings") },
selected = false,
onClick = { }
)
}
}
) {
// Main content
}
}Always-visible drawer for large screens.
@Composable
fun PermanentDrawer() {
PermanentNavigationDrawer(
drawerContent = {
PermanentDrawerSheet {
NavigationDrawerItem(
label = { Text("Dashboard") },
selected = true,
onClick = { }
)
}
}
) {
// Main content
}
}Vertical navigation for tablets and large screens.
@Composable
fun NavRail() {
var selectedItem by remember { mutableIntStateOf(0) }
NavigationRail {
NavigationRailItem(
icon = { Icon(Icons.Default.Home, null) },
label = { Text("Home") },
selected = selectedItem == 0,
onClick = { selectedItem = 0 }
)
NavigationRailItem(
icon = { Icon(Icons.Default.Search, null) },
label = { Text("Search") },
selected = selectedItem == 1,
onClick = { selectedItem = 1 }
)
}
}Expanded navigation rail with more content.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun WideNavRail() {
val railState = rememberWideNavigationRailState()
WideNavigationRail(state = railState) {
WideNavigationRailItem(
railExpanded = railState.isExpanded,
icon = { Icon(Icons.Default.Home, null) },
label = { Text("Home") },
selected = true,
onClick = { }
)
}
}Modal version of wide navigation rail.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ModalWideNavRail() {
ModalWideNavigationRail(
expanded = true,
onCollapse = { /* handle collapse */ }
) {
WideNavigationRailItem(
railExpanded = true,
icon = { Icon(Icons.Default.Settings, null) },
label = { Text("Settings") },
selected = false,
onClick = { }
)
}
}Primary tabs for main content sections.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PrimaryTabs() {
var selectedTab by remember { mutableIntStateOf(0) }
PrimaryTabRow(selectedTabIndex = selectedTab) {
Tab(selected = selectedTab == 0, onClick = { selectedTab = 0 }) {
Text("Tab 1", modifier = Modifier.padding(16.dp))
}
Tab(selected = selectedTab == 1, onClick = { selectedTab = 1 }) {
Text("Tab 2", modifier = Modifier.padding(16.dp))
}
}
}Secondary tabs for sub-sections.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SecondaryTabs() {
var selectedTab by remember { mutableIntStateOf(0) }
SecondaryTabRow(selectedTabIndex = selectedTab) {
Tab(selected = selectedTab == 0, onClick = { selectedTab = 0 }) {
Text("Details")
}
Tab(selected = selectedTab == 1, onClick = { selectedTab = 1 }) {
Text("Reviews")
}
}
}Scrollable primary tabs for many items.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ScrollablePrimaryTabs() {
var selectedTab by remember { mutableIntStateOf(0) }
PrimaryScrollableTabRow(selectedTabIndex = selectedTab) {
repeat(10) { index ->
Tab(
selected = selectedTab == index,
onClick = { selectedTab = index }
) {
Text("Tab $index", modifier = Modifier.padding(16.dp))
}
}
}
}Scrollable secondary tabs.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ScrollableSecondaryTabs() {
var selectedTab by remember { mutableIntStateOf(0) }
SecondaryScrollableTabRow(selectedTabIndex = selectedTab) {
repeat(10) { index ->
Tab(
selected = selectedTab == index,
onClick = { selectedTab = index }
) {
Text("Item $index")
}
}
}
}Floating toolbar for contextual actions.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun FloatingToolbar() {
val state = rememberFloatingToolbarState()
HorizontalFloatingToolbar(
expanded = state.isExpanded,
floatingActionButton = {
FloatingActionButton(onClick = { }) {
Icon(Icons.Default.Add, null)
}
},
content = {
IconButton(onClick = { }) { Icon(Icons.Default.Edit, null) }
IconButton(onClick = { }) { Icon(Icons.Default.Share, null) }
IconButton(onClick = { }) { Icon(Icons.Default.Delete, null) }
}
)
}Vertical floating toolbar.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun VerticalToolbar() {
val state = rememberFloatingToolbarState()
VerticalFloatingToolbar(
expanded = state.isExpanded,
floatingActionButton = {
FloatingActionButton(onClick = { }) {
Icon(Icons.Default.Add, null)
}
},
content = {
IconButton(onClick = { }) { Icon(Icons.Default.Edit, null) }
IconButton(onClick = { }) { Icon(Icons.Default.Share, null) }
}
)
}Basic card container.
@Composable
fun BasicCard() {
Card(
modifier = Modifier.fillMaxWidth()
) {
Column(modifier = Modifier.padding(16.dp)) {
Text("Card Title", style = MaterialTheme.typography.titleLarge)
Text("Card content goes here")
}
}
}Card with elevation.
@Composable
fun ElevatedCardExample() {
ElevatedCard(
modifier = Modifier.fillMaxWidth(),
elevation = CardDefaults.elevatedCardElevation()
) {
Column(modifier = Modifier.padding(16.dp)) {
Text("Elevated Card")
}
}
}Card with outline border.
@Composable
fun OutlinedCardExample() {
OutlinedCard(
modifier = Modifier.fillMaxWidth()
) {
Column(modifier = Modifier.padding(16.dp)) {
Text("Outlined Card")
}
}
}Bottom sheet that appears modally.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BottomSheetExample() {
var showSheet by remember { mutableStateOf(false) }
val sheetState = rememberModalBottomSheetState()
if (showSheet) {
ModalBottomSheet(
onDismissRequest = { showSheet = false },
sheetState = sheetState
) {
// Sheet content
Column(modifier = Modifier.padding(16.dp)) {
Text("Bottom Sheet Content")
}
}
}
}Scaffold with integrated bottom sheet.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BottomSheetScaffoldExample() {
val scaffoldState = rememberBottomSheetScaffoldState()
BottomSheetScaffold(
scaffoldState = scaffoldState,
sheetContent = {
Column(modifier = Modifier.padding(16.dp)) {
Text("Sheet Content")
}
}
) { innerPadding ->
// Main content
}
}Standard alert dialog.
@Composable
fun AlertDialogExample() {
var showDialog by remember { mutableStateOf(false) }
if (showDialog) {
AlertDialog(
onDismissRequest = { showDialog = false },
title = { Text("Dialog Title") },
text = { Text("Dialog message content") },
confirmButton = {
TextButton(onClick = { showDialog = false }) {
Text("Confirm")
}
},
dismissButton = {
TextButton(onClick = { showDialog = false }) {
Text("Cancel")
}
}
)
}
}Basic customizable dialog.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BasicDialogExample() {
var showDialog by remember { mutableStateOf(false) }
if (showDialog) {
BasicAlertDialog(
onDismissRequest = { showDialog = false }
) {
Surface(
shape = MaterialTheme.shapes.large,
tonalElevation = 6.dp
) {
Column(modifier = Modifier.padding(24.dp)) {
Text("Custom Dialog Content")
}
}
}
}
}Chip for smart suggestions.
@Composable
fun AssistChipExample() {
AssistChip(
onClick = { /* action */ },
label = { Text("Assist") },
leadingIcon = {
Icon(Icons.Default.Search, contentDescription = null)
}
)
}Chip for filtering content.
@Composable
fun FilterChipExample() {
var selected by remember { mutableStateOf(false) }
FilterChip(
selected = selected,
onClick = { selected = !selected },
label = { Text("Filter") },
leadingIcon = if (selected) {
{ Icon(Icons.Default.Done, null) }
} else null
)
}Chip representing user input.
@Composable
fun InputChipExample() {
var enabled by remember { mutableStateOf(true) }
if (enabled) {
InputChip(
selected = false,
onClick = { enabled = false },
label = { Text("Input Tag") },
trailingIcon = {
Icon(Icons.Default.Close, null)
}
)
}
}Chip for suggestions.
@Composable
fun SuggestionChipExample() {
SuggestionChip(
onClick = { /* action */ },
label = { Text("Suggestion") }
)
}Elevated assist chip.
@Composable
fun ElevatedAssistChipExample() {
ElevatedAssistChip(
onClick = { /* action */ },
label = { Text("Elevated Assist") }
)
}Elevated filter chip.
@Composable
fun ElevatedFilterChipExample() {
var selected by remember { mutableStateOf(false) }
ElevatedFilterChip(
selected = selected,
onClick = { selected = !selected },
label = { Text("Elevated Filter") }
)
}Elevated suggestion chip.
@Composable
fun ElevatedSuggestionChipExample() {
ElevatedSuggestionChip(
onClick = { /* action */ },
label = { Text("Elevated Suggestion") }
)
}Standard checkbox.
@Composable
fun CheckboxExample() {
var checked by remember { mutableStateOf(false) }
Checkbox(
checked = checked,
onCheckedChange = { checked = it }
)
}Checkbox with three states.
@Composable
fun TriStateCheckboxExample() {
var state by remember { mutableStateOf(ToggleableState.Off) }
TriStateCheckbox(
state = state,
onClick = {
state = when (state) {
ToggleableState.Off -> ToggleableState.Indeterminate
ToggleableState.Indeterminate -> ToggleableState.On
ToggleableState.On -> ToggleableState.Off
}
}
)
}Standard radio button.
@Composable
fun RadioButtonExample() {
val options = listOf("Option 1", "Option 2", "Option 3")
var selected by remember { mutableStateOf(options[0]) }
Column {
options.forEach { option ->
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.clickable { selected = option }
) {
RadioButton(
selected = selected == option,
onClick = { selected = option }
)
Text(option)
}
}
}
}Toggle switch.
@Composable
fun SwitchExample() {
var checked by remember { mutableStateOf(false) }
Switch(
checked = checked,
onCheckedChange = { checked = it },
thumbContent = if (checked) {
{ Icon(Icons.Default.Check, null, Modifier.size(SwitchDefaults.IconSize)) }
} else null
)
}Continuous value slider.
@Composable
fun SliderExample() {
var value by remember { mutableFloatStateOf(0.5f) }
Slider(
value = value,
onValueChange = { value = it },
valueRange = 0f..1f
)
}Slider with range selection.
@Composable
fun RangeSliderExample() {
var range by remember { mutableStateOf(0.2f..0.8f) }
RangeSlider(
value = range,
onValueChange = { range = it },
valueRange = 0f..1f
)
}Vertically oriented slider.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun VerticalSliderExample() {
var value by remember { mutableFloatStateOf(0.5f) }
VerticalSlider(
value = value,
onValueChange = { value = it },
modifier = Modifier.height(200.dp)
)
}Row of segmented buttons for single selection.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SingleChoiceSegmentedButtons() {
var selectedIndex by remember { mutableIntStateOf(0) }
val options = listOf("Day", "Week", "Month")
SingleChoiceSegmentedButtonRow {
options.forEachIndexed { index, label ->
SegmentedButton(
selected = selectedIndex == index,
onClick = { selectedIndex = index },
shape = SegmentedButtonDefaults.itemShape(
index = index,
count = options.size
)
) {
Text(label)
}
}
}
}Row of segmented buttons for multiple selection.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MultiChoiceSegmentedButtons() {
var selectedOptions by remember { mutableStateOf(setOf<Int>()) }
val options = listOf("S", "M", "L", "XL")
MultiChoiceSegmentedButtonRow {
options.forEachIndexed { index, label ->
SegmentedButton(
checked = index in selectedOptions,
onCheckedChange = {
selectedOptions = if (index in selectedOptions) {
selectedOptions - index
} else {
selectedOptions + index
}
},
shape = SegmentedButtonDefaults.itemShape(
index = index,
count = options.size
)
) {
Text(label)
}
}
}
}Connected button group for segmented selection.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ConnectedButtonGroup() {
var selectedIndex by remember { mutableIntStateOf(0) }
val options = listOf("Week", "Month", "Year")
Row(
horizontalArrangement = Arrangement.spacedBy(
ButtonGroupDefaults.ConnectedSpaceBetween
)
) {
options.forEachIndexed { index, label ->
ToggleButton(
checked = selectedIndex == index,
onCheckedChange = { selectedIndex = index },
modifier = Modifier
.weight(1f)
.semantics { role = Role.RadioButton },
shapes = when (index) {
0 -> ButtonGroupDefaults.connectedLeadingButtonShapes()
options.lastIndex -> ButtonGroupDefaults.connectedTrailingButtonShapes()
else -> ButtonGroupDefaults.connectedMiddleButtonShapes()
}
) {
Text(label)
}
}
}
}Parameters for ButtonGroupDefaults:
ConnectedSpaceBetween: Default spacing between connected buttonsconnectedLeadingButtonShapes(): Shapes for the first buttonconnectedMiddleButtonShapes(): Shapes for middle buttonsconnectedTrailingButtonShapes(): Shapes for the last buttonconnectedButtonCheckedShape: Shape when a button is checked
Button group with overflow indicator for many items.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ButtonGroupWithOverflow() {
ButtonGroup(
overflowIndicator = { menuState ->
ButtonGroupDefaults.OverflowIndicator(menuState = menuState)
}
) {
for (i in 0 until 10) {
clickableItem(onClick = {}, label = "$i")
}
}
}Standard filled text field.
@Composable
fun TextFieldExample() {
var text by remember { mutableStateOf("") }
TextField(
value = text,
onValueChange = { text = it },
label = { Text("Label") },
placeholder = { Text("Enter text") }
)
}Text field with outline.
@Composable
fun OutlinedTextFieldExample() {
var text by remember { mutableStateOf("") }
OutlinedTextField(
value = text,
onValueChange = { text = it },
label = { Text("Label") },
placeholder = { Text("Enter text") }
)
}Text field for passwords with visibility toggle.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun SecureTextFieldExample() {
var password by remember { mutableStateOf("") }
SecureTextField(
state = rememberTextFieldState(),
textObfuscationMode = TextObfuscationMode.Hidden,
label = { Text("Password") }
)
}Outlined secure text field.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun OutlinedSecureTextFieldExample() {
OutlinedSecureTextField(
state = rememberTextFieldState(),
textObfuscationMode = TextObfuscationMode.Hidden,
label = { Text("Password") }
)
}Expandable search bar.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SearchBarExample() {
var query by remember { mutableStateOf("") }
var expanded by remember { mutableStateOf(false) }
SearchBar(
inputField = {
SearchBarDefaults.InputField(
query = query,
onQueryChange = { query = it },
onSearch = { expanded = false },
expanded = expanded,
onExpandedChange = { expanded = it },
placeholder = { Text("Search") }
)
},
expanded = expanded,
onExpandedChange = { expanded = it }
) {
// Search suggestions
}
}Search bar that stays docked.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DockedSearchBarExample() {
var query by remember { mutableStateOf("") }
var expanded by remember { mutableStateOf(false) }
DockedSearchBar(
inputField = {
SearchBarDefaults.InputField(
query = query,
onQueryChange = { query = it },
onSearch = { expanded = false },
expanded = expanded,
onExpandedChange = { expanded = it }
)
},
expanded = expanded,
onExpandedChange = { expanded = it }
) {
// Search results
}
}Always-expanded docked search bar.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ExpandedDockedSearchBarExample() {
var query by remember { mutableStateOf("") }
ExpandedDockedSearchBar(
inputField = {
SearchBarDefaults.InputField(
query = query,
onQueryChange = { query = it },
onSearch = { /* handle search */ },
expanded = true,
onExpandedChange = { }
)
}
) {
// Search content
}
}Full-screen search experience.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun FullScreenSearchBarExample() {
var query by remember { mutableStateOf("") }
ExpandedFullScreenSearchBar(
inputField = {
SearchBarDefaults.InputField(
query = query,
onQueryChange = { query = it },
onSearch = { /* handle */ },
expanded = true,
onExpandedChange = { }
)
}
) {
// Full-screen search content
}
}Standard dropdown menu.
@Composable
fun DropdownMenuExample() {
var expanded by remember { mutableStateOf(false) }
Box {
IconButton(onClick = { expanded = true }) {
Icon(Icons.Default.MoreVert, null)
}
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false }
) {
DropdownMenuItem(
text = { Text("Option 1") },
onClick = { expanded = false }
)
DropdownMenuItem(
text = { Text("Option 2") },
onClick = { expanded = false }
)
}
}
}Dropdown attached to a text field.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ExposedDropdownExample() {
var expanded by remember { mutableStateOf(false) }
var selectedOption by remember { mutableStateOf("") }
val options = listOf("Option 1", "Option 2", "Option 3")
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = it }
) {
OutlinedTextField(
value = selectedOption,
onValueChange = { },
readOnly = true,
label = { Text("Select") },
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded) },
modifier = Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable)
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false }
) {
options.forEach { option ->
DropdownMenuItem(
text = { Text(option) },
onClick = {
selectedOption = option
expanded = false
}
)
}
}
}
}Date selection component.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DatePickerExample() {
val state = rememberDatePickerState()
DatePicker(state = state)
}Modal dialog with date picker.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DatePickerDialogExample() {
var showDialog by remember { mutableStateOf(false) }
val state = rememberDatePickerState()
if (showDialog) {
DatePickerDialog(
onDismissRequest = { showDialog = false },
confirmButton = {
TextButton(onClick = { showDialog = false }) {
Text("OK")
}
}
) {
DatePicker(state = state)
}
}
}Range selection for dates.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DateRangePickerExample() {
val state = rememberDateRangePickerState()
DateRangePicker(
state = state,
modifier = Modifier.height(500.dp)
)
}Time selection component.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TimePickerExample() {
val state = rememberTimePickerState()
TimePicker(state = state)
}Keyboard-based time input.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TimeInputExample() {
val state = rememberTimePickerState()
TimeInput(state = state)
}Circular progress indicator.
// Indeterminate
@Composable
fun IndeterminateProgress() {
CircularProgressIndicator()
}
// Determinate
@Composable
fun DeterminateProgress(progress: Float) {
CircularProgressIndicator(progress = { progress })
}Linear progress indicator.
// Indeterminate
@Composable
fun IndeterminateLinearProgress() {
LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
}
// Determinate
@Composable
fun DeterminateLinearProgress(progress: Float) {
LinearProgressIndicator(
progress = { progress },
modifier = Modifier.fillMaxWidth()
)
}Wavy circular progress with expressive motion.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun CircularWavyProgressExample() {
CircularWavyProgressIndicator()
}Wavy linear progress indicator.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun LinearWavyProgressExample() {
LinearWavyProgressIndicator(
progress = { 0.7f },
modifier = Modifier.fillMaxWidth()
)
}General-purpose loading indicator.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun LoadingIndicatorExample() {
LoadingIndicator()
}Loading indicator with container.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ContainedLoadingExample() {
ContainedLoadingIndicator()
}Small badge for notifications.
@Composable
fun BadgeExample() {
Badge { Text("3") }
}Box with badge overlay.
@Composable
fun BadgedBoxExample() {
BadgedBox(
badge = { Badge { Text("99+") } }
) {
Icon(Icons.Default.Notifications, null)
}
}Transient message at bottom of screen.
@Composable
fun SnackbarExample() {
val snackbarHostState = remember { SnackbarHostState() }
Scaffold(
snackbarHost = { SnackbarHost(snackbarHostState) }
) { padding ->
// Content
LaunchedEffect(Unit) {
snackbarHostState.showSnackbar(
message = "Message",
actionLabel = "Undo"
)
}
}
}Container for tooltip display.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TooltipExample() {
TooltipBox(
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
tooltip = { PlainTooltip { Text("Tooltip text") } },
state = rememberTooltipState()
) {
IconButton(onClick = { }) {
Icon(Icons.Default.Info, null)
}
}
}Tooltip with rich content.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun RichTooltipExample() {
TooltipBox(
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
tooltip = {
RichTooltip(
title = { Text("Title") },
action = { TextButton(onClick = { }) { Text("Action") } }
) {
Text("Extended tooltip content")
}
},
state = rememberTooltipState()
) {
IconButton(onClick = { }) {
Icon(Icons.Default.Help, null)
}
}
}Standard list item.
@Composable
fun ListItemExample() {
ListItem(
headlineContent = { Text("Headline") },
supportingContent = { Text("Supporting text") },
leadingContent = {
Icon(Icons.Default.Person, null)
},
trailingContent = {
Icon(Icons.Default.ChevronRight, null)
}
)
}Horizontal divider line.
@Composable
fun HorizontalDividerExample() {
HorizontalDivider()
}Vertical divider line.
@Composable
fun VerticalDividerExample() {
Row {
Text("Left")
VerticalDivider(modifier = Modifier.height(20.dp))
Text("Right")
}
}Basic container surface.
@Composable
fun SurfaceExample() {
Surface(
shape = MaterialTheme.shapes.medium,
tonalElevation = 4.dp
) {
Column(modifier = Modifier.padding(16.dp)) {
Text("Surface content")
}
}
}Swipeable container for dismissible content.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SwipeToDismissExample() {
val dismissState = rememberSwipeToDismissBoxState()
SwipeToDismissBox(
state = dismissState,
backgroundContent = {
Box(
Modifier
.fillMaxSize()
.background(Color.Red)
)
}
) {
ListItem(
headlineContent = { Text("Swipe to dismiss") }
)
}
}Complete expressive theme wrapper.
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ExpressiveTheme(content: @Composable () -> Unit) {
MaterialExpressiveTheme(
colorScheme = if (isSystemInDarkTheme()) {
dynamicDarkColorScheme(LocalContext.current)
} else {
dynamicLightColorScheme(LocalContext.current)
},
motionScheme = MotionScheme.expressive()
) {
content()
}
}@OptIn(ExperimentalMaterial3ExpressiveApi::class)
val expressiveMotion = MotionScheme.expressive()@OptIn(ExperimentalMaterial3ExpressiveApi::class)
val standardMotion = MotionScheme.standard()@ExperimentalMaterial3ExpressiveApi- Required for expressive components@ExperimentalMaterial3Api- Required for some Material 3 components@OptIn- Used to opt-in to experimental APIs
dependencies {
implementation("androidx.compose.material3:material3:1.5.0-alpha10")
}This reference covers the main Material 3 Expressive components. For complete documentation, refer to the official Material 3 documentation.