Scaffold Complete Guide — TopBar, BottomBar, FAB & Drawer Integration
Master Jetpack Compose's Scaffold: the foundational component for Material Design 3 layouts. Learn TopAppBar integration, BottomNavigationBar patterns, Floating Action Buttons, and ModalNavigationDrawer combinations with production-ready code.
1. Basic Scaffold with TopAppBar
The simplest Scaffold pattern: TopAppBar with title, navigation icon, and action buttons.
@Composable
fun BasicScaffoldExample() {
Scaffold(
topBar = {
TopAppBar(
title = { Text("My App") },
navigationIcon = {
IconButton(onClick = { /* navigate back */ }) {
Icon(Icons.Default.ArrowBack, contentDescription = "Back")
}
},
actions = {
IconButton(onClick = { /* search */ }) {
Icon(Icons.Default.Search, contentDescription = "Search")
}
IconButton(onClick = { /* menu */ }) {
Icon(Icons.Default.MoreVert, contentDescription = "More")
}
}
)
},
floatingActionButton = {
FloatingActionButton(onClick = { /* add */ }) {
Icon(Icons.Default.Add, contentDescription = "Add")
}
}
) { paddingValues ->
LazyColumn(modifier = Modifier.padding(paddingValues)) {
items(20) { index ->
Text(
"Item $index",
modifier = Modifier.padding(16.dp)
)
}
}
}
}
Key points:
-
TopAppBartakestitle,navigationIcon,actions -
floatingActionButtonparameter accepts single FAB - Content lambda receives
PaddingValues— always apply to avoid overlap
2. BottomNavigationBar Integration
Add bottom navigation with multiple screens.
enum class BottomNavItem(val route: String, val icon: ImageVector, val label: String) {
Home("home", Icons.Default.Home, "Home"),
Search("search", Icons.Default.Search, "Search"),
Profile("profile", Icons.Default.Person, "Profile")
}
@Composable
fun ScaffoldWithBottomNav() {
var selectedItem by remember { mutableIntStateOf(0) }
val items = BottomNavItem.entries
Scaffold(
topBar = {
TopAppBar(title = { Text("MyApp") })
},
bottomBar = {
NavigationBar {
items.forEachIndexed { index, item ->
NavigationBarItem(
selected = selectedItem == index,
onClick = { selectedItem = index },
icon = { Icon(item.icon, contentDescription = item.label) },
label = { Text(item.label) }
)
}
}
}
) { paddingValues ->
Box(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues),
contentAlignment = Alignment.Center
) {
Text("${items[selectedItem].label} Screen")
}
}
}
3. Collapsing LargeTopAppBar with Scroll Behavior
Implement Material 3 collapsing header for expanded to small transitions.
@Composable
fun CollapsingTopAppBarExample() {
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
LargeTopAppBar(
title = {
Text(
"Large TopBar",
modifier = Modifier.padding(bottom = 16.dp)
)
},
scrollBehavior = scrollBehavior
)
}
) { paddingValues ->
LazyColumn(modifier = Modifier.padding(paddingValues)) {
items(50) { index ->
Card(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
) {
Text("Item $index", modifier = Modifier.padding(16.dp))
}
}
}
}
}
Note: nestedScroll() + scrollBehavior enables smooth collapse animation.
4. Detail Screen Pattern with Action Bar
Back button, share, and delete actions on detail view.
@Composable
fun DetailScreenScaffold(onBack: () -> Unit) {
var showDeleteDialog by remember { mutableStateOf(false) }
Scaffold(
topBar = {
TopAppBar(
title = { Text("Item Details") },
navigationIcon = {
IconButton(onClick = onBack) {
Icon(Icons.Default.ArrowBack, contentDescription = "Back")
}
},
actions = {
IconButton(onClick = { /* share */ }) {
Icon(Icons.Default.Share, contentDescription = "Share")
}
IconButton(onClick = { showDeleteDialog = true }) {
Icon(Icons.Default.Delete, contentDescription = "Delete")
}
}
)
}
) { paddingValues ->
Column(
modifier = Modifier
.padding(paddingValues)
.padding(16.dp)
.verticalScroll(rememberScrollState())
) {
Text("Item Title", style = MaterialTheme.typography.headlineSmall)
Spacer(modifier = Modifier.height(8.dp))
Text("Detailed description here...", style = MaterialTheme.typography.bodyMedium)
}
}
if (showDeleteDialog) {
AlertDialog(
onDismissRequest = { showDeleteDialog = false },
title = { Text("Delete Item?") },
confirmButton = {
Button(onClick = { showDeleteDialog = false; onBack() }) {
Text("Delete")
}
},
dismissButton = {
Button(onClick = { showDeleteDialog = false }) {
Text("Cancel")
}
}
)
}
}
5. ModalNavigationDrawer + Scaffold Combo
Side drawer with Scaffold for navigation.
@Composable
fun DrawerScaffoldExample() {
val drawerState = rememberDrawerState(DrawerValue.Closed)
val scope = rememberCoroutineScope()
var selectedItem by remember { mutableIntStateOf(0) }
ModalNavigationDrawer(
drawerState = drawerState,
drawerContent = {
ModalDrawerSheet {
Text("My App", modifier = Modifier.padding(16.dp), style = MaterialTheme.typography.headlineSmall)
Divider()
listOf("Home", "Settings", "About").forEachIndexed { index, label ->
NavigationDrawerItem(
label = { Text(label) },
selected = selectedItem == index,
onClick = {
selectedItem = index
scope.launch { drawerState.close() }
}
)
}
}
}
) {
Scaffold(
topBar = {
TopAppBar(
title = { Text("Main") },
navigationIcon = {
IconButton(
onClick = { scope.launch { drawerState.open() } }
) {
Icon(Icons.Default.Menu, contentDescription = "Menu")
}
}
)
}
) { paddingValues ->
Box(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues),
contentAlignment = Alignment.Center
) {
Text("Selected: ${listOf("Home", "Settings", "About")[selectedItem]}")
}
}
}
}
Summary
Scaffold is the backbone of Material Design 3 layouts:
- TopAppBar/CenterAlignedTopAppBar/LargeTopAppBar — title & actions
- NavigationBar — bottom navigation
- ModalNavigationDrawer — side navigation
- FloatingActionButton — primary action
- Always apply
PaddingValuesto content to avoid overlap
Use nestedScroll() + scrollBehavior for smooth collapse effects. Chain ModalNavigationDrawer → Scaffold for complex UIs.
8 Android app templates: Gumroad
Top comments (0)