Modifiers are the way to decorate or configure a composable in Compose. They chain together and the order matters.
Modifier ordering
Order matters. Each modifier wraps the one after it.
// Padding is OUTSIDE the background
Modifier
.padding(16.dp) // 16dp padding around the entire thing
.background(Color.Blue) // blue background inside the padding
.padding(8.dp) // 8dp padding between background and text
// vs. background is OUTSIDE the padding
Modifier
.background(Color.Blue)
.padding(16.dp) // padding inside the blue backgroundPadding
// All sides
Modifier.padding(16.dp)
// Different values
Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
// Individual sides
Modifier.padding(start = 8.dp, top = 4.dp, end = 8.dp, bottom = 4.dp)
// Padding around specific content (inside scroll, etc.)
Modifier.padding(innerPadding)Size
// Exact size
Modifier.size(48.dp) // 48 x 48
Modifier.size(width = 200.dp, height = 100.dp)
// Fill parent
Modifier.fillMaxSize() // fill max width and height
Modifier.fillMaxWidth() // fill max width
Modifier.fillMaxHeight() // fill max height
// Constrain size
Modifier.widthIn(min = 100.dp, max = 300.dp)
Modifier.heightIn(min = 50.dp)
Modifier.defaultMinSize(minWidth = 48.dp, minHeight = 48.dp)
// Weight in Row/Column (like LinearLayout weight)
Modifier.weight(1f) // take remaining space
Modifier.weight(2f) // take 2x remaining spaceClick and interaction
// Clickable
Modifier.clickable { /* handle click */ }
// Clickable with indication (ripple)
Modifier.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = ripple(),
) { /* handle click */ }
// Combined clickable (click, long click, double click)
Modifier.pointerInput(Unit) {
detectTapGestures(
onPress = { /* touch down */ },
onTap = { offset -> /* single tap */ },
onDoubleTap = { offset -> /* double tap */ },
onLongPress = { offset -> /* long press */ },
)
}Scrolling
// Vertical scroll (for small content, not LazyColumn)
Modifier.verticalScroll(rememberScrollState())
// Horizontal scroll
Modifier.horizontalScroll(rememberScrollState())
// Scroll to position programmatically
val scrollState = rememberScrollState()
Modifier.verticalScroll(scrollState)
LaunchedEffect(Unit) {
scrollState.animateScrollTo(100)
}
// Nested scrolling is automatic in ComposeClipping and shape
// Clip to shape
Modifier.clip(CircleShape) // circular
Modifier.clip(RoundedCornerShape(12.dp)) // rounded corners
Modifier.clip(RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)) // top only
// Border
Modifier.border(1.dp, Color.Gray, RoundedCornerShape(8.dp))
// Border + clip
Modifier
.clip(RoundedCornerShape(12.dp))
.border(1.dp, MaterialTheme.colorScheme.outline, RoundedCornerShape(12.dp))Background and shadow
// Solid color background
Modifier.background(Color.Blue)
// Background with shape
Modifier.background(Color.Blue, RoundedCornerShape(12.dp))
// Brush background (gradient)
Modifier.background(
Brush.linearGradient(
colors = listOf(Color.Blue, Color.Cyan),
start = Offset(0f, 0f),
end = Offset(1000f, 1000f),
)
)
// Shadow (M3 Card uses elevation)
Modifier.shadow(4.dp, RoundedCornerShape(8.dp))Visibility
// Conditional visibility
if (isVisible) {
Text("Visible content")
}
// Animated visibility
AnimatedVisibility(visible = isVisible) {
Text("Animated content")
}
// Animated visibility with slide
AnimatedVisibility(
visible = isVisible,
enter = slideInVertically() + fadeIn(),
exit = slideOutVertically() + fadeOut(),
) {
Text("Sliding content")
}
// Alpha for semi-hidden
Modifier.alpha(0.5f)Focus and keyboard
val focusRequester = remember { FocusRequester() }
val focusManager = LocalFocusManager.current
Modifier
.focusRequester(focusRequester)
.focusable()
// Request focus
LaunchedEffect(Unit) {
focusRequester.requestFocus()
}
// Clear focus (hide keyboard)
focusManager.clearFocus()
// Handle keyboard actions
TextField(
value = text,
onValueChange = { text = it },
modifier = Modifier
.focusRequester(focusRequester)
.onFocusChanged { state -> isFocused = state.isFocused },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(
onDone = { focusManager.clearFocus() }
),
)Gestures
// Drag
Modifier.draggable(
state = rememberDraggableState { delta -> offset += delta },
orientation = Orientation.Vertical,
)
// Swipe to dismiss
Modifier.swipeToDismiss(
state = rememberSwipeToDismissBoxState(),
directions = setOf(SwipeToDismissBoxDirection.EndToStart),
) { state ->
if (state.currentValue == SwipeToDismissBoxValue.DismissedToEnd ||
state.currentValue == SwipeToDismissBoxValue.DismissedToStart) {
onDismiss()
}
Content()
}
// Transformable (pinch zoom, pan)
Modifier.transformable(state = rememberTransformableState { zoomChange, offsetChange, _ ->
scale *= zoomChange
offset += offsetChange
})
// Scroll with Transformable
Modifier.scrollable(
state = rememberScrollableState { delta -> /* handle */ },
orientation = Orientation.Vertical,
)Common chains
// Card-like surface
Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 4.dp)
.clip(RoundedCornerShape(12.dp))
.background(MaterialTheme.colorScheme.surface)
.clickable { /* ... */ }
.padding(16.dp)
// Avatar
Modifier
.size(48.dp)
.clip(CircleShape)
.background(MaterialTheme.colorScheme.primaryContainer)
// Full-width button
Modifier
.fillMaxWidth()
.height(48.dp)
// List item
Modifier
.fillMaxWidth()
.clickable { /* navigate */ }
.padding(horizontal = 16.dp, vertical = 12.dp)