Package-level declarations

The dialog package provides two composables: AlertDialog for concise confirmations and ModalScaffold for full-screen flows with top/bottom app bars and scrollable content.

Both are annotated @ExperimentalSparkApi.

AlertDialog

A compact dialog for alerting the user or requesting confirmation of a single action.

var showDialog by remember { mutableStateOf(false) }

if (showDialog) {
AlertDialog(
onDismissRequest = { showDialog = false },
title = { Text("Delete listing?") },
text = { Text("This action cannot be undone.") },
confirmButton = {
ButtonGhost(
text = "Delete",
onClick = { viewModel.delete(); showDialog = false },
)
},
dismissButton = {
ButtonGhost(
text = "Cancel",
onClick = { showDialog = false },
)
},
)
}

Parameters

ParameterDefaultDescription
onDismissRequest-Called when the user taps outside the dialog or presses Back
confirmButton-Primary action slot; no click handler is wired automatically
dismissButtonnullSecondary action slot; omit to show a single button
iconnullOptional icon displayed above the title
titlenullDialog headline; omit when body text is self-explanatory
textnullSupporting body text
propertiesDialogProperties()Platform-specific window properties

To prevent dismissal on back press or outside tap, pass a no-op lambda or configure DialogProperties:

AlertDialog(
onDismissRequest = { /* intentionally empty */ },
properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false),
confirmButton = { /* ... */ },
)

Use ButtonGhost for action buttons inside AlertDialog. Filled or outlined buttons are too visually heavy for this compact context.

ModalScaffold

ModalScaffold presents a full-screen flow with a TopAppBar containing a close button, an optional bottom action bar, and scrollable content. On tablets and foldables it renders as a centred modal dialog instead of full-screen.

var showModal by remember { mutableStateOf(false) }

if (showModal) {
ModalScaffold(
onClose = { showModal = false },
title = { Text("Edit profile") },
mainButton = { modifier ->
ButtonFilled(
modifier = modifier,
text = "Save",
onClick = { viewModel.save(); showModal = false },
)
},
supportButton = { modifier ->
ButtonOutlined(
modifier = modifier,
text = "Discard",
onClick = { showModal = false },
)
},
) { innerPadding ->
ProfileForm(modifier = Modifier.padding(innerPadding))
}
}

Parameters

ParameterDefaultDescription
onClose-Invoked when the close button is tapped or the dialog is dismissed
title{}Composable placed in the TopAppBar title slot
actions{}IconButtons placed at the end of the TopAppBar
mainButtonnullPrimary bottom-bar action; receives a Modifier for sizing
supportButtonnullSecondary bottom-bar action; receives a Modifier for sizing
snackbarHost{}Slot for a SnackbarHost
contentPaddingPaddingValues(horizontal = 24.dp)Padding applied around content
inEdgeToEdgefeature flagSet true when the host activity is edge-to-edge

Dismiss behaviour

The close (X) button in the top bar calls onClose. On phone portrait and landscape it also dismisses when the user presses Back. On tablets it dismisses on outside tap. To prevent dismissal, pass a no-op onClose lambda.

Layout adaptation

ModalScaffold picks a layout automatically based on LocalWindowSizeClass:

ContextLayout
Phone portraitFull-screen Scaffold with stacked buttons
Phone landscapeFull-screen Scaffold with side-by-side buttons
Tablet / foldableCentred dialog (280-560dp wide), large shape

Bottom bar

Omit both mainButton and supportButton to hide the bottom bar entirely. This is useful for informational modals that need only the close button.

ModalScaffold(
onClose = { showModal = false },
title = { Text("Terms of service") },
// No mainButton or supportButton - bottom bar hidden
) { innerPadding ->
TermsContent(Modifier.padding(innerPadding))
}

Snackbar

Pass a SnackbarHost to snackbarHost to display in-modal feedback:

val snackbarHostState = remember { SnackbarHostState() }

ModalScaffold(
onClose = { showModal = false },
snackbarHost = { SnackbarHost(snackbarHostState) },
mainButton = { modifier ->
ButtonFilled(modifier = modifier, text = "Submit", onClick = {
scope.launch { snackbarHostState.showSnackbar("Saved") }
})
},
) { innerPadding ->
FormContent(Modifier.padding(innerPadding))
}

Types

Link copied to clipboard

Functions

Link copied to clipboard
fun AlertDialog(onDismissRequest: () -> Unit, confirmButton: @Composable () -> Unit, modifier: Modifier = Modifier, dismissButton: @Composable () -> Unit? = null, icon: @Composable () -> Unit? = null, title: @Composable () -> Unit? = null, text: @Composable () -> Unit? = null, shape: Shape = AlertDialogDefaults.shape, containerColor: Color = AlertDialogDefaults.containerColor, iconContentColor: Color = AlertDialogDefaults.iconContentColor, titleContentColor: Color = AlertDialogDefaults.titleContentColor, textContentColor: Color = AlertDialogDefaults.textContentColor, tonalElevation: Dp = AlertDialogDefaults.TonalElevation, properties: DialogProperties = DialogProperties())

Spark AlertDialog.

Link copied to clipboard
fun ModalScaffold(onClose: () -> Unit, modifier: Modifier = Modifier, contentPadding: PaddingValues = DialogPadding, contentWindowInsets: WindowInsets = ScaffoldDefaults.contentWindowInsets, snackbarHost: @Composable () -> Unit = {}, mainButton: @Composable (Modifier) -> Unit? = null, supportButton: @Composable (Modifier) -> Unit? = null, title: @Composable () -> Unit = {}, actions: @Composable RowScope.() -> Unit = {}, inEdgeToEdge: Boolean = LocalSparkFeatureFlag.current.isContainingActivityEdgeToEdge, content: @Composable (PaddingValues) -> Unit)

A composable function that creates a full-screen modal scaffold, adapting its layout based on the device's screen size and orientation.