List-detail layout
Shows a list and the selected item side by side, or one after the other on small windows.
- Category: Layout and structure
- API status: Expressive
- Compose APIs:
ListDetailPaneScaffold,AnimatedPane,rememberListDetailPaneScaffoldNavigator,ListDetailPaneScaffoldRole - Interactive page: https://m3e.ljzapps.app/#components/list-detail
When to use
ListDetailPaneScaffold is the canonical layout for master and detail content such as mail or contacts. The window size decides how many panes are visible. On a compact window the detail pane replaces the list, on larger windows both are shown.
The navigator remembers the selected item and the back stack, so back navigation closes the detail pane first. Resize the browser window to watch the layout adapt.
Examples
Contacts
Resize the window to switch between one and two panes.
val navigator = rememberListDetailPaneScaffoldNavigator<String>()
val scope = rememberCoroutineScope()
val names = listOf("Maya Chen", "Jonas Weber", "Ana Silva", "Kenji Sato")
Box(Modifier.fillMaxWidth().height(340.dp)) {
ListDetailPaneScaffold(
directive = navigator.scaffoldDirective,
scaffoldState = navigator.scaffoldState,
listPane = {
AnimatedPane {
Box(Modifier.fillMaxSize()) {
LazyColumn {
items(names) { name ->
ListItem(
onClick = { scope.launch { navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, name) } },
supportingContent = { Text("Tap to open") },
) { Text(name) }
}
}
}
}
},
detailPane = {
AnimatedPane {
Box(Modifier.fillMaxSize().padding(24.dp), contentAlignment = Alignment.Center) {
val selected = navigator.currentDestination?.contentKey
if (selected == null) {
Text("Select a contact", style = MaterialTheme.typography.bodyLarge)
} else {
Text(selected, style = MaterialTheme.typography.headlineMedium)
}
}
}
},
)
}
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
directive | PaneScaffoldDirective | navigator.scaffoldDirective | Derived from the window size class and posture. |
scaffoldState | ThreePaneScaffoldState | navigator.scaffoldState | Which panes are visible. |
listPane / detailPane | @Composable ThreePaneScaffoldPaneScope.() -> Unit | Wrap content in AnimatedPane. | |
extraPane | @Composable (...)? | null | Optional third pane for large windows. |
Guidelines
Do:
- Keep the list scroll position when going back.
- Show an empty state in the detail pane.
Don't:
- Do not duplicate the selected item's title in both panes.
- Do not use it for unrelated content.
Accessibility
- When the detail pane replaces the list, move focus to it and return focus to the selected item on back.
- The back button of the browser should close the detail pane. Wire the navigator into your navigation.