Expressive buttons in Jetpack Compose
Shape morph on press
Section titled “Shape morph on press”Button has a new overload that takes shapes: ButtonShapes. Pass ButtonDefaults.shapes() and
the button is round at rest and squarer while pressed, animated by the theme’s fast spatial
spring. Without shapes you get the old fixed-shape button.
@Composablefun MorphingButton(onClick: () -> Unit) { // Passing `shapes` switches to the overload whose corners morph (round -> square) on press. Button(onClick = onClick, shapes = ButtonDefaults.shapes()) { Text("Continue") }}FilledTonalButton, ElevatedButton, OutlinedButton and TextButton have the same overload.
Five sizes
Section titled “Five sizes”| Size | Height | Icon | Constant |
|---|---|---|---|
| Extra small | 32dp | 20dp | ButtonDefaults.ExtraSmallContainerHeight |
| Small (default) | 40dp | 20dp | ButtonDefaults.MinHeight |
| Medium | 56dp | 24dp | ButtonDefaults.MediumContainerHeight |
| Large | 96dp | 32dp | ButtonDefaults.LargeContainerHeight |
| Extra large | 136dp | 40dp | ButtonDefaults.ExtraLargeContainerHeight |
For anything other than the default, size every part from the same height with the …For(height) helpers:
@Composablefun MediumCta(icon: ImageVector, onClick: () -> Unit) { // Sizes: ExtraSmall 32dp, Small 40dp (default), Medium 56dp, Large 96dp, ExtraLarge 136dp. val height = ButtonDefaults.MediumContainerHeight Button( onClick = onClick, modifier = Modifier.heightIn(height), shapes = ButtonDefaults.shapesFor(height), contentPadding = ButtonDefaults.contentPaddingFor(height, hasStartIcon = true), ) { Icon(icon, contentDescription = null, modifier = Modifier.size(ButtonDefaults.iconSizeFor(height))) Spacer(Modifier.size(ButtonDefaults.iconSpacingFor(height))) Text("Start free trial", style = ButtonDefaults.textStyleFor(height)) }}When to use which
Section titled “When to use which”- One medium or large button for the main action of a screen, like “Start free trial” on a paywall.
- Default size for everything else. Two large buttons side by side compete for attention.
Common mistakes
Section titled “Common mistakes”- Setting
Modifier.height(56.dp)withoutshapesFor,contentPaddingForandtextStyleFor. The label and corners then stay sized for 40dp. - Passing
shape =and expecting the press morph. The morph only comes withshapes =.
Accessibility
Section titled “Accessibility”Text buttons need no extra semantics. Icon-only buttons belong in icon buttons.
Related: toggle buttons · button groups · motion springs
Want your agent to get this right every time? Install the skill. If this page helped,star the repo on GitHub.
Built by Sanikant. Set in Google Sans Flex (SIL Open Font License), icons from Material Symbols (Apache 2.0). Material Design is a Google trademark; this project is not affiliated with Google.