Skip to main content
Scaffold provides a standard layout structure with slots for common UI elements like top bars, bottom bars, floating action buttons, and snackbars. It handles proper positioning and padding automatically.

Parameters

modifier
Modifier
default:"Modifier"
Modifier to be applied to the scaffold
topBar
@Composable () -> Unit
default:"{}"
Top app bar composable, typically a TopBar component
bottomBar
@Composable () -> Unit
default:"{}"
Bottom bar composable, typically a NavigationBar
snackbarHost
@Composable () -> Unit
default:"{}"
Snackbar host for displaying snackbars
floatingActionButton
@Composable () -> Unit
default:"{}"
Floating action button composable
floatingActionButtonPosition
FabPosition
default:"FabPosition.End"
Position of the FAB. Can be FabPosition.End or FabPosition.Center
containerColor
Color
default:"AppTheme.colors.background"
Background color of the scaffold
contentColor
Color
default:"contentColorFor(containerColor)"
Color for content inside the scaffold
contentWindowInsets
WindowInsets
default:"ScaffoldDefaults.contentWindowInsets"
Window insets to be applied to the content
content
@Composable (PaddingValues) -> Unit
required
Main content of the scaffold. Receives PaddingValues to account for top and bottom bars

Usage Examples

Basic Scaffold

Scaffold { paddingValues ->
    Column(
        modifier = Modifier
            .padding(paddingValues)
            .fillMaxSize()
    ) {
        Text("Main content")
    }
}

Scaffold with Top Bar

Scaffold(
    topBar = {
        TopBar {
            Text("App Title")
        }
    }
) { paddingValues ->
    // Content automatically padded to account for top bar
    LazyColumn(
        modifier = Modifier.padding(paddingValues)
    ) {
        items(20) {
            Text("Item $it")
        }
    }
}

Scaffold with Bottom Navigation

var selectedItem by remember { mutableStateOf(0) }

Scaffold(
    bottomBar = {
        NavigationBar {
            NavigationBarItem(
                selected = selectedItem == 0,
                onClick = { selectedItem = 0 },
                icon = { Icon(Icons.Default.Home, null) },
                label = { Text("Home") }
            )
            NavigationBarItem(
                selected = selectedItem == 1,
                onClick = { selectedItem = 1 },
                icon = { Icon(Icons.Default.Search, null) },
                label = { Text("Search") )
            )
        }
    }
) { paddingValues ->
    Box(modifier = Modifier.padding(paddingValues)) {
        // Content
    }
}

Scaffold with FAB

Scaffold(
    floatingActionButton = {
        FloatingActionButton(
            onClick = { /* Add action */ }
        ) {
            Icon(Icons.Default.Add, contentDescription = "Add")
        }
    },
    floatingActionButtonPosition = FabPosition.End
) { paddingValues ->
    // Content
}

Complete Scaffold

val snackbarHostState = remember { SnackbarHostState() }

Scaffold(
    topBar = {
        TopBar {
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween,
                verticalAlignment = Alignment.CenterVertically
            ) {
                IconButton(onClick = { /* Menu */ }) {
                    Icon(Icons.Default.Menu, null)
                }
                Text("My App")
                IconButton(onClick = { /* Settings */ }) {
                    Icon(Icons.Default.Settings, null)
                }
            }
        }
    },
    bottomBar = {
        NavigationBar {
            // Navigation items
        }
    },
    snackbarHost = {
        SnackbarHost(snackbarHostState)
    },
    floatingActionButton = {
        FloatingActionButton(onClick = { /* Action */ }) {
            Icon(Icons.Default.Add, null)
        }
    }
) { paddingValues ->
    LazyColumn(
        modifier = Modifier
            .padding(paddingValues)
            .fillMaxSize()
    ) {
        // List content
    }
}

Scaffold with Custom Colors

Scaffold(
    containerColor = Color(0xFF1E1E1E),
    contentColor = Color.White,
    topBar = { /* ... */ }
) { paddingValues ->
    // Dark themed content
}

FAB Positioning

The FAB can be positioned in two ways:
// End position (default - bottom-right in LTR, bottom-left in RTL)
Scaffold(
    floatingActionButtonPosition = FabPosition.End,
    floatingActionButton = { /* FAB */ }
) { }

// Center position (bottom-center)
Scaffold(
    floatingActionButtonPosition = FabPosition.Center,
    floatingActionButton = { /* FAB */ }
) { }

Window Insets

Scaffold automatically handles system bars and window insets:
// Use default insets (system bars)
Scaffold(
    contentWindowInsets = ScaffoldDefaults.contentWindowInsets
) { }

// Custom insets
Scaffold(
    contentWindowInsets = WindowInsets(left = 16.dp, right = 16.dp)
) { }

// No insets
Scaffold(
    contentWindowInsets = WindowInsets(0.dp)
) { }

Features

  • Automatic Layout: Handles positioning of top bar, bottom bar, FAB, and snackbar
  • Smart Padding: Content receives PaddingValues that account for bars
  • Window Insets: Proper handling of system bars and notches
  • Z-ordering: Correct layering of components (content, top bar, snackbar, bottom bar, FAB)
  • RTL Support: Proper layout in right-to-left languages
  • FAB Integration: FAB positioning accounts for bottom bar presence

Best Practices

  1. Always use the provided PaddingValues: Apply the padding from the content lambda to avoid content being hidden behind bars
Scaffold { paddingValues ->
    LazyColumn(modifier = Modifier.padding(paddingValues)) {
        // Content
    }
}
  1. Snackbar positioning: Snackbars automatically position themselves above the FAB or bottom bar
  2. Top bar with scrolling: Combine with TopBar scroll behaviors for collapsing headers

Source Reference

Scaffold component implementation: components-lab/src/commonMain/kotlin/com/nomanr/lumo/ui/components/Scaffold.kt

Build docs developers (and LLMs) love