Scaffold is a composable function in Jetpack Compose that implements the basic screen structure according to the Material Design specification. Scaffold provides slots for TopAppBar, BottomBar, FloatingActionButton, Drawer and Snackbar. According to Google Android Documentation, 2025, Scaffold is a required element for most screens in Compose applications, as it manages insets for Material Design system components.
Key Takeaways
Scaffold is a composable function that implements the screen scaffold according to the Material Design specification. Scaffold is not a container in the traditional sense — it is a layout manager that coordinates the placement of several standard Material components on the screen.
Scaffold manages insets for TopAppBar, BottomBar and FloatingActionButton, as well as system elements — the status bar and navigation bar. This ensures that content does not overlap with system elements and complies with Material Design guidelines.
According to Material Design Guidelines, 2025, Scaffold should be the root element of every application screen. It replaces the deprecated CoordinatorLayout from the View system and provides a simpler, declarative API for building screen layouts.
Scaffold accepts the parameters modifier, scaffoldState, topBar, bottomBar, floatingActionButton, drawerContent, snackbarHost and content. The content parameter receives PaddingValues — insets that the main content must account for.
@Composable
fun BasicScaffold() {
Scaffold(
topBar = {
TopAppBar(
title = { Text("Home") }
)
},
floatingActionButton = {
FloatingActionButton(onClick = {}) {
Icon(Icons.Default.Add, contentDescription = "Add")
}
}
) { innerPadding ->
Column(
modifier = Modifier.padding(innerPadding)
) {
Text("Main content")
}
}
}
topBar is the slot for placing the top app bar, typically TopAppBar or LargeTopAppBar. Scaffold automatically adds insets to innerPadding for content so it does not overlap with topBar. TopAppBar can contain a title, a navigation icon and actions.
bottomBar is the slot for the bottom navigation bar. It supports BottomNavigation, BottomAppBar or NavigationBar. Scaffold accounts for bottomBar height when calculating innerPadding for content. According to Material Design Guidelines, 2025, bottomBar should be used on screens with 3–5 navigation points.
floatingActionButton is the slot for the floating action button. Scaffold automatically positions the FAB according to the Material Design specification — in the bottom right corner with correct insets. floatingActionButtonPosition allows moving the FAB to the center of the bottom edge of the screen.
In this example, Scaffold uses all the main slots: TopAppBar with a title, BottomBar with three navigation items and FloatingActionButton for the primary action.
@Composable
fun FullScaffold() {
Scaffold(
topBar = {
TopAppBar(
title = { Text("App") },
navigationIcon = {
IconButton(onClick = {}) {
Icon(Icons.Default.Menu, "Menu")
}
}
)
},
bottomBar = {
NavigationBar {
NavigationBarItem(
icon = { Icon(Icons.Default.Home, "Home") },
label = { Text("Home") },
selected = true,
onClick = {}
)
NavigationBarItem(
icon = { Icon(Icons.Default.Search, "Search") },
label = { Text("Search") },
selected = false,
onClick = {}
)
}
},
floatingActionButton = {
FloatingActionButton(onClick = {}) {
Icon(Icons.Default.Add, "Add")
}
}
) { innerPadding ->
Box(modifier = Modifier.padding(innerPadding)) {
Text("Screen content")
}
}
}
ScaffoldState is the state object of Scaffold that combines DrawerState and SnackbarHostState. DrawerState manages opening and closing the side menu, while SnackbarHostState manages displaying and hiding the Snackbar. The state is created using rememberScaffoldState() and passed to the scaffoldState parameter.
DrawerState provides open and close methods for programmatic Drawer control. The Drawer state can be open, closed or partially open. drawerGesturesEnabled allows disabling the swipe gesture to open the Drawer, leaving only programmatic opening via a button.
SnackbarHostState manages the Snackbar — temporary notifications at the bottom of the screen. The showSnackbar method displays a Snackbar with a message and an optional action. According to Material Design Guidelines, 2025, Snackbar should be used for brief messages without critically important information.
@Composable
fun ScaffoldWithDrawer() {
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = scaffoldState,
topBar = {
TopAppBar(
title = { Text("Menu") },
navigationIcon = {
IconButton(onClick = {
scope.launch {
scaffoldState.drawerState.open()
}
}) {
Icon(Icons.Default.Menu, "Menu")
}
}
)
},
drawerContent = {
Column(modifier = Modifier.padding(16.dp)) {
Text("Item 1")
Text("Item 2")
}
}
) { innerPadding ->
Box(modifier = Modifier.padding(innerPadding)) {
Text("Content")
}
}
}
A complete screen example with Scaffold includes TopAppBar, BottomNavigation, FloatingActionButton and Snackbar for displaying notifications when the FAB is pressed. ScaffoldState is passed to all components for state coordination.
@Composable
fun MainScreen() {
val state = rememberScaffoldState()
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = state,
topBar = {
TopAppBar(
title = { Text("IT Sectr") },
actions = {
IconButton(onClick = {}) {
Icon(Icons.Default.Notifications, "Notifications")
}
}
)
},
bottomBar = {
NavigationBar {
NavigationBarItem(icon = { Icon(Icons.Default.Home, "Home") },
label = { Text("Home") }, selected = true, onClick = {})
NavigationBarItem(icon = { Icon(Icons.Default.Settings, "Settings") },
label = { Text("Settings") }, selected = false, onClick = {})
}
},
floatingActionButton = {
FloatingActionButton(onClick = {
scope.launch {
state.snackbarHostState.showSnackbar("Done")
}
}) {
Icon(Icons.Default.Add, "Add")
}
}
) { padding ->
Box(
modifier = Modifier.padding(padding).fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text("Welcome")
}
}
}
innerPadding is the PaddingValues that Scaffold passes to the content block. They contain insets needed to prevent content from overlapping with statusBar, navigationBar, topBar and bottomBar. Using innerPadding is required for correct display on different devices.
Scaffold automatically calculates innerPadding based on system insets and the height of installed slots. On devices with camera cutouts or display notches, Scaffold adjusts insets for the status bar. On older devices with physical buttons, the bottom inset may be absent.
According to Android Developers, 2024, innerPadding should be applied to the root content container via Modifier.padding(innerPadding). If the content uses a scrollable container, innerPadding is applied via Modifier.consumeWindowInsets for correct keyboard and system gesture behavior.
Frequently Asked Questions
Scaffold is not a container but a layout manager that controls slots for TopAppBar, BottomBar, FAB, Drawer and Snackbar, and also automatically handles insets for system components. Column and Box only position elements without considering Material Design.
Scaffold is recommended for screens that use Material Design components. On simple screens without TopAppBar, BottomBar or FAB, Scaffold is not required, but it provides correct system insets via innerPadding, which is useful even without slots.
Pass ScaffoldState to the scaffoldState parameter of Scaffold, then call state.snackbarHostState.showSnackbar(“Message”) inside a coroutine. Scaffold will automatically display the Snackbar at the bottom of the screen.
Yes, Scaffold creates internal state by default if scaffoldState is not passed. However, to programmatically control Drawer and Snackbar, you need to create and pass ScaffoldState via rememberScaffoldState().
Use the floatingActionButtonPosition parameter of Scaffold. By default, the FAB is located at the bottom right (FabPosition.End). Set FabPosition.Center to place the FAB at the center of the bottom edge of the screen.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also