Compose Fundamentals Part 2: Mastering Modifiers
BeginnerFundamentalsModifierTutorial
What Are Modifiers?
In XML, you set properties like width, height, margin, and background directly on Views. In Compose, all of this is done through Modifiers.
Modifiers are the Swiss Army knife of Compose. They can: set size and position, add padding and margins, apply backgrounds and borders, handle clicks and gestures, and much more.
Modifier Chaining
Modifiers are chained together using the dot notation. Each modifier wraps the previous one, like layers of an onion:
@Composable
fun StyledBox() {
Box(
modifier = Modifier
.size(200.dp) // Size: 200x200dp
.background(Color.Blue) // Fill with blue
.padding(16.dp) // Inner padding
.background(Color.Red) // Inner red box
) {
Text("Hello!", color = Color.White)
}
}Note: The blue background covers the full 200dp, but the red background only covers the area inside the 16dp padding. Order matters!
Essential Layout Modifiers
Here are the modifiers you will use in almost every Composable:
Modifier
// Size
.size(100.dp) // Fixed width and height
.width(200.dp) // Fixed width only
.height(50.dp) // Fixed height only
.fillMaxWidth() // Match parent width
.fillMaxHeight() // Match parent height
.fillMaxSize() // Match both
.wrapContentSize() // Wrap content
// Spacing
.padding(16.dp) // Padding on all sides
.padding(horizontal = 8.dp, vertical = 16.dp)
.padding(start = 8.dp, top = 4.dp, end = 8.dp, bottom = 4.dp)
// Alignment (in Box)
.align(Alignment.Center) // Center in parent BoxStyling Modifiers
Modifiers also handle visual styling:
Modifier
// Background
.background(Color.Blue)
.background(Color.Blue, RoundedCornerShape(8.dp))
.background(brush = Brush.verticalGradient(listOf(Color.Blue, Color.Cyan)))
// Border
.border(2.dp, Color.Black)
.border(2.dp, Color.Black, RoundedCornerShape(8.dp))
// Shape clipping
.clip(RoundedCornerShape(8.dp))
.clip(CircleShape)
// Shadow (must come before clip/background)
.shadow(4.dp, RoundedCornerShape(8.dp))Interaction Modifiers
Making things interactive is also done through modifiers:
Modifier
// Click handling
.clickable { onClick() }
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple() // Ripple effect
) { onClick() }
// Scroll
.verticalScroll(rememberScrollState())
.horizontalScroll(rememberScrollState())The Order Rule
Modifier order is crucial. The rule is: "Outer modifiers apply first, inner modifiers apply last." This catches many beginners:
// ❌ WRONG: Padding is outside clickable, so edges don't respond to taps
Modifier
.padding(16.dp)
.clickable { }
// ✅ RIGHT: Clickable area includes the padding
Modifier
.clickable { }
.padding(16.dp)Note: When debugging layout issues, try reordering your modifiers. The visual result can change dramatically.