Intermediate: Android basics · Jetpack Compose UI · topic 22 of 50 · 30 min
Composables and modifiers
Explanation
Building blocks
A Compose screen is a tree of composables. You combine small built-in ones into your own, the same way you combine words into sentences. Here are the ones you will use every day:
@Composable
fun ProductRow() {
Row(verticalAlignment = Alignment.CenterVertically) {
Image(
painter = painterResource(R.drawable.tiffin),
contentDescription = "Steel tiffin box",
modifier = Modifier.size(64.dp),
)
Column(Modifier.padding(start = 12.dp)) {
Text("Steel tiffin box", style = MaterialTheme.typography.titleMedium)
Text("Rs 349", color = MaterialTheme.colorScheme.primary)
}
Spacer(Modifier.weight(1f))
IconButton(onClick = { /* add to cart */ }) {
Icon(Icons.Default.Add, contentDescription = "Add to cart")
}
}
}| Composable | Shows |
|---|---|
| Text | Text, with a style from the theme |
| Button / OutlinedButton / TextButton | Clickable buttons with an onClick lambda |
| Image | A picture from resources (painterResource) or loaded from the internet with a library such as Coil |
| Icon / IconButton | Material icons, optionally clickable |
| Spacer | Empty space |
Modifiers
Almost every composable has a modifier parameter. A Modifier is built by chaining functions: Modifier.fillMaxWidth().padding(16.dp).background(Color.White). Each function adds one decoration or behaviour. Common ones: size, width, height, fillMaxWidth, fillMaxSize, padding, background, border, clip (round the corners), clickable, and weight (inside Row/Column).
Order matters
// Padding OUTSIDE the background: the coloured box is smaller, with a gap around it
Text("A", Modifier.padding(16.dp).background(Color.Yellow))
// Padding INSIDE the background: the coloured box is bigger, with space around the text
Text("B", Modifier.background(Color.Yellow).padding(16.dp))
// Clickable area: only the inner area responds here
Text("C", Modifier.padding(16.dp).clickable { })By convention, every reusable composable you write takes modifier: Modifier = Modifier as a parameter and passes it to its outermost element. The caller can then add padding or size from outside without you changing the composable, exactly like the built-in ones.
dp and sp
Phones have very different pixel densities. dp (density-independent pixels) are a unit that looks about the same physical size on every screen; use it for sizes, padding and spacing. sp (scale-independent pixels) are like dp but also grow when the user increases the font size in system settings; use it for text sizes. Never use raw pixels for layout.
Content descriptions
contentDescription describes an image or icon for screen readers such as TalkBack, which blind and low-vision users rely on. Describe meaningful images ("Add to cart"); pass null for purely decorative ones. This is also checked by Play's pre-launch accessibility report.
Common mistakes
- Getting modifier order wrong, for example clickable before padding when you wanted the whole padded area clickable. Put clickable first in that case.
- Hard-coding colours like Color.Red everywhere. Use MaterialTheme.colorScheme so dark mode and branding work (module 9).
- Using dp for text size. Use sp so text follows the user's font setting.
- Leaving out contentDescription on icon buttons, which makes them unusable with a screen reader.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Composables and modifiers · 1/6
Screens are built from small composables: Text, Button, Image and Icon.
Prefer a video by a teacher? Find free videos on “jetpack compose modifiers order text image button tutorial” on YouTube ↗
In real life: A product card on a shopping app
An online saree shop shows each product as a card: image, name, price and a heart button. The card is one composable, ProductCard, used in the home feed, search results and wishlist. A change to the card (say, showing a discount badge) appears everywhere at once, and modifiers give it consistent padding and rounded corners.
@Composable
fun PriceTag(price: Int, modifier: Modifier = Modifier) {
Text(
text = "Rs $price",
fontSize = 18.sp,
modifier = modifier
.clip(RoundedCornerShape(8.dp))
.background(MaterialTheme.colorScheme.primaryContainer)
.padding(horizontal = 12.dp, vertical = 4.dp),
)
}Practice (0/3 done)
Which modifier chain makes the whole padded area clickable?
Which unit should a text size use?
Build a ContactRow composable: a round avatar (an Icon in a Box clipped with CircleShape and a background), the name and phone number in a Column, and a call IconButton at the end. Make two previews and try swapping the order of padding and background to see the difference.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- State and recompositionJetpack Compose UI · same module
- Layouts: Column, Row, Box and ScaffoldJetpack Compose UI · same module
- Lists and gridsJetpack Compose UI · same module
- Accessibility and adaptive layoutsPermissions, Material 3 and polish
- Compose UI testsTesting Android apps
- Access modifiers, static members and encapsulationC# and .NET · Classes and objects
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What is a Modifier?
Answer: A chain of instructions that changes a composable's look or behaviour
Modifiers decorate and add behaviour.
What does dp stand for and why use it?
Answer: Density-independent pixels; sizes look similar on all screens
dp scales with screen density.
What should contentDescription be for a purely decorative image?
Answer: null
null tells screen readers to skip it.
How do you read a modifier chain?
Answer: Left to right, outside in
Each modifier wraps what follows it.
Which window width class do most phones in portrait have?Related
Can you call a @Composable function inside a click handler?Related
Answer: No; change state and let the UI recompose
Composables can only be called from other composables.
Why test stateless "Content" composables directly?Related
Answer: You can show any state without a real ViewModel, server or database
Easy setup of exact states.
From Compose UI tests
Where can Modifier.weight be used?Related
Answer: Inside Row and Column
weight belongs to RowScope and ColumnScope.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 4 more topics in “Jetpack Compose UI” before its exam: State and recomposition, Layouts: Column, Row, Box and Scaffold, Lists and grids, Text input and forms.
- Module 6 exam: Jetpack Compose UI · 13 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Navigation and app architecture. 50 topics left in the course before the final exam.