Modifiers in Jetpack Compose — Basic Concepts to Get You Started

Neil Davies
The Startup
5 min readNov 25, 2020

--

Jetpack Compose is a new UI toolkit for android (and desktop) that uses a declarative syntax much like Flutter, React and even swiftUI. Currently it’s rapidly evolving through various alpha releases, with a beta release scheduled for early to mid 2021.

It’s definitely not ready for production code yet, with APIs still changing between alpha releases and a few performance issues to iron out. Even so, this UI toolkit already has a lot of powerful features that can be explored, allowing developers to create some great looking and functional UI’s, so it’s well worth looking into now.

With this new UI toolkit comes a few new concepts that are worth getting familiar with, and one of these is Modifiers.

What are Modifiers?

All UI emitting composables can have a Modifier parameter. Modifiers allow us to change how a composable is presented, they let you:

  • Change the composables behaviour and appearance
  • Add information like accessibility labels
  • Process user input
  • Add high-level interactions like making an element clickable, scrollable, draggable or zoomable.

If you’re already an Android developer you’ll be familiar with defining views in XML and in many cases modifiers are analogous to layout parameters in view-based layouts. But there are some important advantages to modifiers. Since modifiers are scope-specific, they offer type safety and also help you to discover and understand what is available and applicable to a certain layout. With XML layouts, it is sometimes hard to find out if a particular layout attribute is applicable to a given view.

Modifier examples

As we’ve already implied, modifiers can be used in quite a wide variety of ways most commonly we’ll chain calls to modifiers together here’s a simple example of a modifier for an Image.

Example Circular image composeable with a modifier applying border, padding and circular clip
Example code for a circular image using a modifier

Looking at the code we can see that we have an Image Composable that takes a Modifier as a parameter. To create an instance of the Modifier we use a Modifier object and make chained calls to the methods on that object. In this case we set up a border then some padding and lastly we clip the image, this gives a circular image inside a circular border with padding in between. But what would happen if we changed the calling order of the border and padding functions? Let’s take a look.

Modifier ordering

The ordering of how we call modifiers is important and will change the result of how composables are modified. Taking the previous example, let’s swap the border and padding function calls.

Example code showing how ordering of modifiers is important

The order that modifier functions are called defines the order in which they are applied to the composable. Here we apply the padding first, then the border and lastly the clip. This means that the padding is now outside the border and not in between the border and the image as it was in the previous example.

In the case of applying padding, ordering means that we no longer need the concept of margins that apply to the “outside” of a view. Now we simply apply the padding first, and this gives the same result as using a margin in the old view based system.

Ordering of modifiers gives more control to achieve the exact behaviour we want and the outcome is explicit and predictable.

Modifier scope

Another interesting and useful feature of Modifiers is Scope. Let’s take a look at an example where we have a Row composable layout that contains two Text composables.

Because the Texts are in the Row Scope we can now also call align on the Modifier

Row composables lay out their children across the screen one after each other in a row. But if we give the Row a height greater than its children we also have the possibility of aligning these children vertically.

It makes sense that our modifiers now have a method for alignment, with the ability to pass in arguments of type vertical alignment.

In this case we now have the additional alignment functions available on the modifiers because we are calling them from within RowScope, and this scope has the additional align extension functions defined.

Here we use the modifier align functions to vertically centre both our Texts. You’ll also see a similar scope behaviour with other layout composables such as Column and Constraint. The scopes will define additional Modifier methods that will only be available when the Modifiers you are using are within the corresponding scope.

Compared to layout params in XML this makes Modifiers more discoverable, easier to use, and type safe.

Making composeables reusable with default modifiers

When creating your own composables you’ll find that it is often a good idea to add a modifier parameter to your composable functions. A lot of composables provided by the compose library follow this convention.

As an example let’s take a look at our circular image composable again.

Using a default modifier parameters to make composables reusable

Here we’ve added in a Modifier as the last parameter to our composable function and we’ve also given it a default value of an empty Modifier making it an optional parameter. We then reuse this modified in the body of our composable.

As a result of adding this parameter we can now specify additional Modifiers outside of our component. This allows users of this composable to add modifiers to decorate or position this composable, making it much more reusable. As an example if we wanted to use our circular image composable in a Row layout we may want to be able to align it. Giving the option of passing in a Modifier allows us to do so.

Go forth and modify!

So there you have it, that was our quick tour of Modifiers. In this post we’ve covered just some of the basic things that you can do with them. It’s worthwhile taking some time to learn more about Modifiers as they are a key component of Compose. They’re used extensively throughout the compose framework, and if you keep in mind some key concepts — such as ordering and scopes, you’ll find them much easier and safer to use than the good old layout parameters we’ve been using up until now.

--

--