Ever run into weird layout bugs or mysteriously unclickable components in Jetpack Compose? The culprit might be how you're stacking your modifiers β especially when you're conditionally adding them. Let's fix that, once and for all.
π‘ Use Case: Conditionally Clickable Cards
Imagine you're building a PermissionCard composable like this one above in the pic:
@Composable
fun PermissionCard(
icon: ImageVector,
title: String,
description: String,
showSwitch: Boolean = true,
switchChecked: Boolean = false,
onSwitchToggle: ((Boolean) -> Unit)? = null,
modifier: Modifier = Modifier,
onClick: (() -> Unit)? = null
) {
Surface(
shape = MaterialTheme.shapes.medium,
color = colorResource(id = R.color.carraraColor),
modifier = modifier
.then(
if (onClick != null) {
Modifier.clickable { onClick() }
} else {
Modifier
}
)
.fillMaxWidth()
.padding(all = basePadding)
) {
........ more codeβ Why this is the right way:
- π Modifiers are immutable
Each
.padding(),.clickable(), etc., returns a newModifier. You're building a chain, not mutating a single object. - π§±
then()stacks modifiers safely Using.then(...)lets you conditionally add a modifier without restarting or overriding the modifier chain. - π Conditional logic stays clean
Avoids deeply nested
ifstatements and keeps your modifier logic declarative.
π« What not to do:
.then(
if (onClick != null) modifier.clickable { onClick() } else modifier
)- β You're reusing
modifierinside itself - β You might duplicate layout modifiers
- β Leads to unexpected or buggy behavior
π§ͺ Real Example: Privacy Policy Card
This PermissionCard gets reused for various settings β like navigating to my Privacy Policy:
@Composable
fun PrivacyPolicyCard(navController: NavController) {
val encodedUrl = URLEncoder.encode("https://...", StandardCharsets.UTF_8)
PermissionCard(
icon = Icons.Default.Lock,
title = "Privacy Policy",
description = "Read our policy to understand\nhow we use your data.",
showSwitch = false,
onClick = { navController.navigate(...createRoute(encodedUrl)) }
)
}By using .then(...), my PermissionCard only becomes clickable when onClick is passed, without affecting layout or requiring awkward branching logic.
βοΈ Final Thoughts
When building reusable components:
- Use
then(...)for conditional modifiers. - Always pass a fresh
Modifier, not the one you're building. - Keep layout and interaction modifiers cleanly separated.
π Use Modifier.then() the smart way β and never wonder why your clicks stopped working again.
π± Like What You're Seeing?
If you've enjoyed this dive into Modifier.then() and how I'm building clean, reusable UI in Jetpack Compose...
π Check out what I'm building on Google Play!
It's a sports-focused app built entirely with Jetpack Compose β including components like the PermissionCard you saw in this post.
Your support means a lot, so leave a review if you have a moment β I'd love your feedback!
π£οΈ: reach out on LinkedIn, X or Insta
Best, Rafa