Dialog
A modal window for a decision or a small task that needs the user's attention.
- Category: Containment
- API status: Stable
- Compose APIs:
AlertDialog,BasicAlertDialog,AlertDialogDefaults - Interactive page: https://m3e.ljzapps.app/#components/dialog
When to use
Dialogs interrupt the flow, so reserve them for important choices such as confirming a destructive action. Use AlertDialog for the standard icon, title, text and two buttons, and BasicAlertDialog for custom content such as a list of choices.
Buttons are text buttons. The confirming action goes on the right and uses a verb that names the result.
Playground
The interactive page has a playground with live property controls for this component and generated code.
Examples
Confirmation
Standard AlertDialog.
var open by rememberSaveable { mutableStateOf(false) }
Button(onClick = { open = true }) { Text("Delete draft") }
if (open) {
AlertDialog(
onDismissRequest = { open = false },
icon = { Icon(Icons.Rounded.Delete, contentDescription = null) },
title = { Text("Delete this draft?") },
text = { Text("The draft and its attachments are removed. This cannot be undone.") },
confirmButton = { TextButton(onClick = { open = false }) { Text("Delete") } },
dismissButton = { TextButton(onClick = { open = false }) { Text("Cancel") } },
)
}
Single choice
BasicAlertDialog with custom content.
var open by rememberSaveable { mutableStateOf(false) }
val options = listOf("Phone ringtone", "Alarm", "Silent")
var selected by rememberSaveable { mutableStateOf(options.first()) }
Button(onClick = { open = true }) { Text("Notification sound") }
if (open) {
BasicAlertDialog(onDismissRequest = { open = false }) {
Surface(shape = MaterialTheme.shapes.extraLarge, tonalElevation = 6.dp) {
Column(Modifier.padding(24.dp)) {
Text("Notification sound", style = MaterialTheme.typography.headlineSmall)
Column(Modifier.selectableGroup().padding(vertical = 16.dp)) {
options.forEach { option ->
Row(
Modifier
.fillMaxWidth()
.selectable(option == selected, onClick = { selected = option }, role = Role.RadioButton),
verticalAlignment = Alignment.CenterVertically,
) {
RadioButton(selected = option == selected, onClick = null)
Text(option, Modifier.padding(start = 16.dp, top = 12.dp, bottom = 12.dp))
}
}
}
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) {
TextButton(onClick = { open = false }) { Text("Cancel") }
TextButton(onClick = { open = false }) { Text("OK") }
}
}
}
}
}
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
onDismissRequest | () -> Unit | Called on scrim click, back or Escape. | |
confirmButton | @Composable () -> Unit | The affirmative action. | |
dismissButton | @Composable (() -> Unit)? | null | The neutral or negative action. |
icon / title / text | @Composable (() -> Unit)? | null | Optional content slots. |
properties | DialogProperties | DialogProperties() | Dismiss on back and outside click, platform behavior. |
Guidelines
Do:
- Ask one question per dialog.
- Name the confirming action with a verb.
Don't:
- Do not open a dialog from another dialog.
- Do not use a dialog for information that is not actionable.
Accessibility
- Focus moves into the dialog when it opens and returns to the trigger when it closes.
- The title is announced first. Without a title, make the text self explanatory.
- Escape and the scrim dismiss the dialog. Do not remove both without offering a visible way out.