---
title: "Scaffold"
description: "Scaffold implements the basic Material Design visual layout structure."
type: "component"
---

<div class='type'>Composable Component</div>



Scaffold implements the basic Material Design visual layout structure.

<a id='references'></a>

<div class='sourceset sourceset-common'>Common</div>


```kotlin
@Composable
fun Scaffold(
    contentWindowInsets: WindowInsets,
    modifier: Modifier = Modifier,
    scaffoldState: ScaffoldState = rememberScaffoldState(),
    topBar: @Composable () -> Unit = {},
    bottomBar: @Composable () -> Unit = {},
    snackbarHost: @Composable (SnackbarHostState) -> Unit = { SnackbarHost(it) },
    floatingActionButton: @Composable () -> Unit = {},
    floatingActionButtonPosition: FabPosition = FabPosition.End,
    isFloatingActionButtonDocked: Boolean = false,
    drawerContent: @Composable (ColumnScope.() -> Unit)? = null,
    drawerGesturesEnabled: Boolean = true,
    drawerShape: Shape = MaterialTheme.shapes.large,
    drawerElevation: Dp = DrawerDefaults.Elevation,
    drawerBackgroundColor: Color = MaterialTheme.colors.surface,
    drawerContentColor: Color = contentColorFor(drawerBackgroundColor),
    drawerScrimColor: Color = DrawerDefaults.scrimColor,
    backgroundColor: Color = MaterialTheme.colors.background,
    contentColor: Color = contentColorFor(backgroundColor),
    content: @Composable (PaddingValues) -> Unit,
)
```


#### Parameters

| | |
| --- | --- |
| contentWindowInsets | window insets to be passed to `content` slot via `PaddingValues` params. Scaffold will take the insets into account from the top/bottom only if the `topBar`/ `bottomBar` are not present, as the scaffold expect `topBar`/`bottomBar` to handle insets instead. Any insets consumed by other insets padding modifiers or `consumeWindowInsets` on a parent layout will be excluded from `contentWindowInsets`. |
| modifier | optional Modifier for the root of the `Scaffold` |
| scaffoldState | state of this scaffold widget. It contains the state of the screen, e.g. variables to provide manual control over the drawer behavior, sizes of components, etc |
| topBar | top app bar of the screen. Consider using `TopAppBar`. |
| bottomBar | bottom bar of the screen. Consider using `BottomAppBar`. |
| snackbarHost | component to host `Snackbar`s that are pushed to be shown via `SnackbarHostState.showSnackbar`. Usually it's a `SnackbarHost` |
| floatingActionButton | Main action button of your screen. Consider using `FloatingActionButton` for this slot. |
| floatingActionButtonPosition | position of the FAB on the screen. See `FabPosition` for possible options available. |
| isFloatingActionButtonDocked | whether `floatingActionButton` should overlap with `bottomBar` for half a height, if `bottomBar` exists. Ignored if there's no `bottomBar` or no `floatingActionButton`. |
| drawerContent | content of the Drawer sheet that can be pulled from the left side (right for RTL). |
| drawerGesturesEnabled | whether or not drawer (if set) can be interacted with via gestures |
| drawerShape | shape of the drawer sheet (if set) |
| drawerElevation | drawer sheet elevation. This controls the size of the shadow below the drawer sheet (if set) |
| drawerBackgroundColor | background color to be used for the drawer sheet |
| drawerContentColor | color of the content to use inside the drawer sheet. Defaults to either the matching content color for `drawerBackgroundColor`, or, if it is not a color from the theme, this will keep the same value set above this Surface. |
| drawerScrimColor | color of the scrim that obscures content when the drawer is open |
| backgroundColor | background of the scaffold body |
| contentColor | color of the content in scaffold body. Defaults to either the matching content color for `backgroundColor`, or, if it is not a color from the theme, this will keep the same value set above this Surface. |
| content | content of your screen. The lambda receives an `PaddingValues` that should be applied to the content root via `androidx.compose.foundation.layout.padding` and `androidx.compose.foundation.layout.consumeWindowInsets` to properly offset top and bottom bars. If using `androidx.compose.foundation.verticalScroll`, apply this modifier to the child of the scroll, and not on the scroll itself. |




<div class='sourceset sourceset-common'>Common</div>


```kotlin
@Composable
fun Scaffold(
    modifier: Modifier = Modifier,
    scaffoldState: ScaffoldState = rememberScaffoldState(),
    topBar: @Composable () -> Unit = {},
    bottomBar: @Composable () -> Unit = {},
    snackbarHost: @Composable (SnackbarHostState) -> Unit = { SnackbarHost(it) },
    floatingActionButton: @Composable () -> Unit = {},
    floatingActionButtonPosition: FabPosition = FabPosition.End,
    isFloatingActionButtonDocked: Boolean = false,
    drawerContent: @Composable (ColumnScope.() -> Unit)? = null,
    drawerGesturesEnabled: Boolean = true,
    drawerShape: Shape = MaterialTheme.shapes.large,
    drawerElevation: Dp = DrawerDefaults.Elevation,
    drawerBackgroundColor: Color = MaterialTheme.colors.surface,
    drawerContentColor: Color = contentColorFor(drawerBackgroundColor),
    drawerScrimColor: Color = DrawerDefaults.scrimColor,
    backgroundColor: Color = MaterialTheme.colors.background,
    contentColor: Color = contentColorFor(backgroundColor),
    content: @Composable (PaddingValues) -> Unit,
)
```


#### Parameters

| | |
| --- | --- |
| modifier | optional Modifier for the root of the `Scaffold` |
| scaffoldState | state of this scaffold widget. It contains the state of the screen, e.g. variables to provide manual control over the drawer behavior, sizes of components, etc |
| topBar | top app bar of the screen. Consider using `TopAppBar`. |
| bottomBar | bottom bar of the screen. Consider using `BottomAppBar`. |
| snackbarHost | component to host `Snackbar`s that are pushed to be shown via `SnackbarHostState.showSnackbar`. Usually it's a `SnackbarHost` |
| floatingActionButton | Main action button of your screen. Consider using `FloatingActionButton` for this slot. |
| floatingActionButtonPosition | position of the FAB on the screen. See `FabPosition` for possible options available. |
| isFloatingActionButtonDocked | whether `floatingActionButton` should overlap with `bottomBar` for half a height, if `bottomBar` exists. Ignored if there's no `bottomBar` or no `floatingActionButton`. |
| drawerContent | content of the Drawer sheet that can be pulled from the left side (right for RTL). |
| drawerGesturesEnabled | whether or not drawer (if set) can be interacted with via gestures |
| drawerShape | shape of the drawer sheet (if set) |
| drawerElevation | drawer sheet elevation. This controls the size of the shadow below the drawer sheet (if set) |
| drawerBackgroundColor | background color to be used for the drawer sheet |
| drawerContentColor | color of the content to use inside the drawer sheet. Defaults to either the matching content color for `drawerBackgroundColor`, or, if it is not a color from the theme, this will keep the same value set above this Surface. |
| drawerScrimColor | color of the scrim that obscures content when the drawer is open |
| backgroundColor | background of the scaffold body |
| contentColor | color of the content in scaffold body. Defaults to either the matching content color for `backgroundColor`, or, if it is not a color from the theme, this will keep the same value set above this Surface. |
| content | content of your screen. The lambda receives an `PaddingValues` that should be applied to the content root via `androidx.compose.foundation.layout.padding` and `androidx.compose.foundation.layout.consumeWindowInsets` to properly offset top and bottom bars. If using `androidx.compose.foundation.verticalScroll`, apply this modifier to the child of the scroll, and not on the scroll itself. |






## Code Examples
### ScaffoldWithBottomBarAndCutout
```kotlin
@Composable
fun ScaffoldWithBottomBarAndCutout() {
    val scaffoldState = rememberScaffoldState()
    // Consider negative values to mean 'cut corner' and positive values to mean 'round corner'
    val sharpEdgePercent = -50f
    val roundEdgePercent = 45f
    // Start with sharp edges
    val animatedProgress = remember { Animatable(sharpEdgePercent) }
    // Create a coroutineScope for the animation
    val coroutineScope = rememberCoroutineScope()
    // animation value to animate shape
    val progress = animatedProgress.value.roundToInt()
    // When progress is 0, there is no modification to the edges so we are just drawing a rectangle.
    // This allows for a smooth transition between cut corners and round corners.
    val fabShape =
        if (progress < 0) {
            CutCornerShape(abs(progress))
        } else if (progress == roundEdgePercent.toInt()) {
            CircleShape
        } else {
            RoundedCornerShape(progress)
        }
    // lambda to call to trigger shape animation
    val changeShape: () -> Unit = {
        val target = animatedProgress.targetValue
        val nextTarget = if (target == roundEdgePercent) sharpEdgePercent else roundEdgePercent
        coroutineScope.launch {
            animatedProgress.animateTo(
                targetValue = nextTarget,
                animationSpec = TweenSpec(durationMillis = 600),
            )
        }
    }
    Scaffold(
        scaffoldState = scaffoldState,
        drawerContent = { Text("Drawer content") },
        topBar = { TopAppBar(title = { Text("Scaffold with bottom cutout") }) },
        bottomBar = {
            BottomAppBar(cutoutShape = fabShape) {
                IconButton(
                    onClick = { coroutineScope.launch { scaffoldState.drawerState.open() } }
                ) {
                    Icon(Icons.Filled.Menu, contentDescription = "Localized description")
                }
            }
        },
        floatingActionButton = {
            ExtendedFloatingActionButton(
                text = { Text("Change shape") },
                onClick = changeShape,
                shape = fabShape,
            )
        },
        contentWindowInsets = ScaffoldDefaults.contentWindowInsets,
        floatingActionButtonPosition = FabPosition.Center,
        isFloatingActionButtonDocked = true,
        content = { innerPadding ->
            LazyColumn(contentPadding = innerPadding) {
                items(count = 100) {
                    Box(Modifier.fillMaxWidth().height(50.dp).background(colors[it % colors.size]))
                }
            }
        },
    )
}
```
### ScaffoldWithSimpleSnackbar
```kotlin
@Composable
fun ScaffoldWithSimpleSnackbar() {
    val scaffoldState = rememberScaffoldState()
    val scope = rememberCoroutineScope()
    Scaffold(
        scaffoldState = scaffoldState,
        floatingActionButton = {
            var clickCount by remember { mutableStateOf(0) }
            ExtendedFloatingActionButton(
                text = { Text("Show snackbar") },
                onClick = {
                    // show snackbar as a suspend function
                    scope.launch {
                        scaffoldState.snackbarHostState.showSnackbar("Snackbar # ${++clickCount}")
                    }
                },
            )
        },
        contentWindowInsets = ScaffoldDefaults.contentWindowInsets,
        content = { innerPadding ->
            Text(
                text = "Body content",
                modifier = Modifier.padding(innerPadding).fillMaxSize().wrapContentSize(),
            )
        },
    )
}
```
### SimpleScaffoldWithTopBar
```kotlin
@Composable
fun SimpleScaffoldWithTopBar() {
    val scaffoldState = rememberScaffoldState()
    val scope = rememberCoroutineScope()
    Scaffold(
        scaffoldState = scaffoldState,
        drawerContent = { Text("Drawer content") },
        topBar = {
            TopAppBar(
                title = { Text("Simple Scaffold Screen") },
                navigationIcon = {
                    IconButton(onClick = { scope.launch { scaffoldState.drawerState.open() } }) {
                        Icon(Icons.Filled.Menu, contentDescription = "Localized description")
                    }
                },
            )
        },
        floatingActionButtonPosition = FabPosition.End,
        floatingActionButton = {
            ExtendedFloatingActionButton(
                text = { Text("Inc") },
                onClick = { /* fab click handler */ },
            )
        },
        contentWindowInsets = ScaffoldDefaults.contentWindowInsets,
        content = { innerPadding ->
            LazyColumn(contentPadding = innerPadding) {
                items(count = 100) {
                    Box(Modifier.fillMaxWidth().height(50.dp).background(colors[it % colors.size]))
                }
            }
        },
    )
}
```

