
If you've ever built a layout in Jetpack Compose and needed a clean, predictable gap between two elements, the Jetpack Compose's Spacer composable is the tool for the job. The Jetpack Compose Spacer is a dedicated empty layout element whose only purpose is to take up space, and once you understand how Jetpack Compose's Spacer works, adding consistent gaps to a Row, a Column, or a Box becomes almost effortless. A Jetpack Compose Spacer doesn't draw anything and doesn't hold any content of its own — it simply reserves room, which makes the Jetpack Compose's Spacer one of the most predictable spacing tools available to developers working anywhere in the Jetpack ecosystem.
In this blog, you'll learn exactly what the Jetpack Compose Spacer composable does, how to size a Jetpack Compose's Spacer with different modifiers, how to make a Jetpack Compose Spacer flexible so it grows to fill leftover space, and how the Jetpack Compose's Spacer fits into a real layout. Every example below is self-contained, so you can paste it straight into an online Kotlin compiler that supports Jetpack Compose and see the Jetpack Compose Spacer composable in action.
The Jetpack Compose's Spacer composable is a function that Compose provides specifically to create blank space in a layout. Unlike Row, Column, or Box, the Jetpack Compose Spacer does not accept a content lambda — it has nothing to draw and nothing to arrange. The entire job of a Jetpack Compose's Spacer is described by a single parameter, and Jetpack's own layout composables all follow this same modifier-driven sizing convention.
Here's the basic signature of the Jetpack Compose Spacer composable:
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun BasicSpacerExample() {
Spacer(modifier = Modifier.width(24.dp))
}
When this code runs, Compose creates an invisible layout node that occupies twenty four density-independent pixels of horizontal space and nothing else. Notice that the Jetpack Compose's Spacer takes only one parameter, modifier, and that parameter defaults to Modifier with no size at all. That detail matters: a Jetpack Compose Spacer with no size modifier attached collapses to zero width and zero height, so it becomes invisible and has no effect on your layout. Every time you reach for a Jetpack Compose's Spacer, pair it with a sizing modifier such as width, height, or size, otherwise the empty space composable does nothing. Whichever spacer modifier you choose, Compose measures it during the same layout pass as every other child.
The most common place to use a Jetpack Compose horizontal spacer is inside a Row, where elements sit side by side and you want a consistent gap between them. Modifier.width tells the Jetpack Compose Spacer exactly how wide that gap should be, measured in dp.
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun HorizontalSpacerRow() {
Row {
Text("Username")
Spacer(modifier = Modifier.width(16.dp))
Text("Password")
}
}
Running this composable places two text labels in a horizontal row with a fixed sixteen dp gap sitting between them. Because the Jetpack Compose horizontal spacer only defines a width, Compose ignores its height inside a Row — the row's own height still comes from its tallest child. This is why a Jetpack Compose's Spacer sized with width is the natural choice whenever you're laying out icons, buttons, or labels next to each other and want the same visual rhythm every time. This mirrors how every other Jetpack layout primitive expects size to be declared through a modifier rather than a parameter.
Flip the scenario around and you get the Jetpack Compose vertical spacer pattern, which is used inside a Column to separate stacked elements. Instead of width, attach Modifier.height to the Jetpack Compose Spacer.
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun VerticalSpacerColumn() {
Column {
Text("Order confirmed")
Spacer(modifier = Modifier.height(20.dp))
Text("Your items will ship within two business days")
}
}
This snippet stacks two lines of text with twenty dp of vertical breathing room between them. A Jetpack Compose vertical spacer behaves the same way as its horizontal counterpart, just on the opposite axis — inside a Column, the Jetpack Compose's Spacer's height reserves the gap while its width is effectively ignored because a Column measures each child's own width separately. Developers reach for a Jetpack Compose Spacer constantly when building forms, cards, and list items where text needs consistent vertical rhythm instead of being crammed together. Jetpack's Column and Row share this same measurement model, which keeps spacing behavior predictable across both axes.
Sometimes a gap needs both a width and a height, especially inside a Box where children can overlap in two dimensions. Modifier.size lets a single call configure both measurements on a Jetpack Compose's Spacer at once.
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun BoxedSpacerExample() {
Box {
Spacer(modifier = Modifier.size(width = 40.dp, height = 40.dp))
}
}
Modifier.size accepts either a single dp value that applies to both dimensions, or separate width and height arguments like the example above. This gives the Jetpack Compose Spacer a fixed forty by forty dp footprint, which is handy when reserving room for something that loads later, like an image or an avatar placeholder, without the surrounding layout jumping around once that content appears. Jetpack's Box composable measures children independently on both axes, which is exactly why a two-dimensional size call is necessary here.
So far every Jetpack Compose's Spacer has had a fixed size, but a Jetpack Compose Spacer becomes far more powerful when paired with the weight modifier inside a Row or Column. A weighted Jetpack Compose's Spacer doesn't reserve a fixed number of dp — instead, it expands to consume whatever space is left over after every other sibling has been measured.
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@Composable
fun WeightedSpacerRow() {
Row(modifier = Modifier.fillMaxWidth()) {
Text("Left label")
Spacer(modifier = Modifier.weight(1f))
Text("Right label")
}
}
Because the spacer weight modifier claims all of the remaining horizontal space, "Left label" gets pushed to the start of the row and "Right label" gets pushed all the way to the end, with the Jetpack Compose Spacer invisibly stretching between them. This only works inside a RowScope or ColumnScope, since weight is an extension function defined on those scopes rather than on Modifier generally. Nest two weighted Jetpack Compose's Spacer elements around a single element and that element ends up centered, because each spacer weight modifier claims an equal share of the leftover room on either side. Jetpack introduced the weight modifier specifically to solve proportional space distribution without manual pixel math.
Let's put several of these ideas together in a scenario you'll run into constantly: a toolbar that needs a title on the left, a flexible gap in the middle, and an action icon fixed to the right. Working out the Jetpack Compose Spacer width height combination for a layout like this is a great way to see the Jetpack Compose's Spacer earning its keep.
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun ToolbarWithSpacer() {
Row(
modifier = Modifier.fillMaxWidth().padding(12.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text("Dashboard")
Spacer(modifier = Modifier.weight(1f))
Icon(imageVector = Icons.Filled.Settings, contentDescription = "Settings")
Spacer(modifier = Modifier.width(12.dp))
}
}
This toolbar uses two Jetpack Compose Spacer elements doing two different jobs. The first is a weighted Jetpack Compose's Spacer that pushes the settings icon to the far end of the row, while the second is a small fixed-width Jetpack Compose Spacer that keeps the icon from sitting flush against the row's edge. Combining a flexible Jetpack Compose's Spacer with a fixed-size Jetpack Compose Spacer in the same layout is an extremely common pattern once you start building real toolbars, headers, and list rows. Patterns like this show up constantly across real Jetpack-based Android apps, from settings screens to dashboards.
Beyond width, height, size, and weight, a handful of smaller details are worth knowing about the Jetpack Compose's Spacer that don't each need their own section.
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun MultipleSpacersExample() {
Column {
Text("Step 1: Enter details")
Spacer(modifier = Modifier.height(8.dp))
Text("Step 2: Confirm order")
Spacer(modifier = Modifier.height(24.dp))
Text("Step 3: Track shipment")
}
}
This column shows two different dp spacing Jetpack Compose values in the same layout: a tight eight dp gap between closely related steps, and a wider twenty four dp gap before the final step to visually group the first two together. Stacking several sized Jetpack Compose's Spacer elements like this is one of the simplest ways to build a sense of visual hierarchy without touching padding on any individual text element.
| Modifier | Axis affected | Typical container | Behavior |
|---|---|---|---|
| Modifier.width(dp) | Horizontal only | Row | Reserves a fixed horizontal gap |
| Modifier.height(dp) | Vertical only | Column | Reserves a fixed vertical gap |
| Modifier.size(dp) | Both | Box | Reserves a fixed width and height together |
| Modifier.weight(f) | Whichever axis the parent lays out on | Row or Column | Expands to fill all remaining leftover space |
Each row in this table maps to one of the sizing approaches a Jetpack Compose Spacer supports, and picking the right one usually comes down to whether an android compose spacer example needs a fixed gap or a flexible one that adapts to the available room. Jetpack has kept these four modifiers stable across every stable release, so the table above holds regardless of version.
Here's a full, self-contained example that combines a fixed vertical Jetpack Compose's Spacer, a fixed horizontal Jetpack Compose Spacer, and a weighted Jetpack Compose's Spacer inside one small profile card layout, so you can see the Jetpack Compose Spacer composable handling several jobs at once.
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
Surface {
ProfileCardWithSpacers()
}
}
}
}
}
@Composable
fun ProfileCardWithSpacers() {
Column(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
Text("Jordan Lee")
Spacer(modifier = Modifier.height(4.dp))
Text("Product Designer")
Spacer(modifier = Modifier.height(20.dp))
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Text("Followers: 128")
Spacer(modifier = Modifier.weight(1f))
Text("Following")
Spacer(modifier = Modifier.width(8.dp))
Text("54")
}
}
}
When this activity runs, the name and job title stack with a small four dp gap between them, a larger twenty dp gap separates that block from the stats row below, and inside the stats row a weighted Jetpack Compose's Spacer pushes the follower count to one side and the following count to the other while a small eight dp Jetpack Compose Spacer keeps the two numbers from touching. Together these three spacers show how a single Jetpack Compose's Spacer composable, sized in three different ways, handles nearly every spacing job in a Compose layout. Building layouts this way is a good example of the composition-first mindset Jetpack encourages throughout its libraries.