I'm learning Jetpack Compose with an official tutorial that states:
It's a best practice to have your Composable accept a Modifier parameter, and pass that modifier to its first child.
And they provide examples where a @Composable
function uses the modifier
parameter given by its parent, chains new modifier elements to it, and passes that to its child components.
e.g:
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier.padding(bottom = 16.dp)
)
}
However, in a later exercise in the provided solution code, the modifier
parameter (with a lowercase m
) is mostly unused, and instead, a new instatiation of Modifier
(with an uppercase M
) is typically used.
What is actually the best practice? When do I use the modifier
parameter, and when do I create a new instantiation of Modifier
?
I'm learning Jetpack Compose with an official tutorial that states:
It's a best practice to have your Composable accept a Modifier parameter, and pass that modifier to its first child.
And they provide examples where a @Composable
function uses the modifier
parameter given by its parent, chains new modifier elements to it, and passes that to its child components.
e.g:
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier.padding(bottom = 16.dp)
)
}
However, in a later exercise in the provided solution code, the modifier
parameter (with a lowercase m
) is mostly unused, and instead, a new instatiation of Modifier
(with an uppercase M
) is typically used.
What is actually the best practice? When do I use the modifier
parameter, and when do I create a new instantiation of Modifier
?
1 Answer
Reset to default 6All composable functions that emit UI1 should take a parameter of type Modifier
as their first optional parameter. Optional means that it has a default value and therefore you do not need to pass such a parameter when you call the function.
Your example function contains the word modifier three times, each time meaning something different:
fun Greeting(name: String, modifier: Modifier = Modifier)
- The name of the parameter is
modifier
. - The parameter type is
Modifier
. - The default value is the object
Modifier
(which has, of course, also the typeModifier
). You could use any other Modifier object, but for the default value you shouldn't, it should always be the object that is namedModifier
, a global object that represents an empty modifier.
Now, inside your composable you should use this modifier
parameter and apply it to the first UI element you use2. In your example that is the Text composable. It has a modifier parameter of its own that is declared identical to how your Greeting function declares it.
In your example, you not only pass your modifier
parameter to Text, you add another modifier first, effectively creating a modifier chain:
Text(
text = "Hello $name!",
modifier = modifier.padding(bottom = 16.dp)
)
But you could also simply pass the parameter through:
Text(
text = "Hello $name!",
modifier = modifier
)
(where the first word modifier is the parameter name of Text and the second is the actual modifier object that was passed to Greeting)
You could also use this (with a capital M
):
Text(
text = "Hello $name!",
modifier = Modifier
)
It compiles just fine, but now you do not use the modifier
parameter that was passed to Greeting anymore, you use the global Modifier
object. Since that is the same as the default value declared by Text you could omit it altogether:
Text(
text = "Hello $name!"
)
Conclusion: Use modifier
when you want to use the actual object that was passed to your function (it may contain any modifier or modifier chain). Use Modifier
when you want to access the global Modifier that is empty and doesn't actually modify anything. You mostly use it as a default value or as the starting point of a modifier chain.
1 That are composables like Column, Text, or most of the custom composables you will create, but not remember
and the likes; they are composable functions but they do not emit UI.
2 Only use it on the first element, do not use it on any other elements. For more See the official API Guidelines for @Composable
components in Jetpack Compose.
modifier
on the root composable. Can you include the "other usage" you're talking about here in the question? – ianhanniballake Commented Jan 18 at 16:26ComposableInfoCard
within the provided solution code I linked in the OP as an example:Column(modifier = modifier.fillMaxSize().background(backgroundColor).padding(16.dp)
Here the function gives the lowercasemodifier
parameter and passes it onto theColumn
composable. Later in the same function, there is the code:Text(text = title,modifier = Modifier.padding(bottom = 16.dp), /* ... */
Here the functions gives the uppercaseModifier
object and passes it onto the theText
composable. – Toldry Commented Jan 19 at 4:47Modifier.padding(16.dp)
, you'd only want to apply that padding in one place, not in multiple places, right? Is your question about what element the passed in element should be applied to? If so, that's the part that is already consistent between the two: to the root composable. – ianhanniballake Commented Jan 19 at 4:57modifier
and when to useModifier
– Toldry Commented Jan 19 at 4:59