Jetpack Compose

Hero image for Jetpack Compose

These guidelines outline the best practices and conventions for building native UI with Jetpack Compose.

Project structure

Defining packages for theme, style, etc.

...
├── ui
│   ├── components
│   │   └── Button.kt
│   ├── modifiers
│   │   └── Modifiers.kt
│   ├── theme
│   │   ├── Colors.kt
│   │   ├── Dimens.kt
│   │   ├── Shapes.kt
│   │   ├── Themes.kt
│   │   └── Typography.kt
│   ├── screens
│   │   └── HomeScreen.kt
...

Modifiers

Several conventions apply to the Modifiers parameter, as mentioned below:

  • The modifier parameter must be named as “modifier”.
  • The modifier parameter must appear as the first optional parameter in the composable function’s parameter list.

Composable functions must NOT accept multiple Modifier parameters.

@Composable
fun LoginButton(
  modifier: Modifier = Modifier
) {}

State and Event

Following official best practices, use remember if possible to minimize expensive calculations whenever the composable functions are recomposed.

@Composable
fun LoginButton(
  modifier: Modifier = Modifier
) {
  val rememberLoginState = remember { mutableStateOf(loginState) }
  LoginButton(modifier) {
    enabled = rememberLoginState
  }
}
@Composable
fun LoginButton(
  modifier: Modifier = Modifier
) {
  LoginButton(modifier) {
    enabled = mutableStateOf(loginState)
  }
}

Conventions

Naming Unit @Composable functions as entities

The names of composable functions as entities must be a noun, but may be prefixed by descriptive adjectives written in PascalCase.

  • Naming composable functions for screens
@Composable
fun HomeScreen() {}
@Composable
fun homeScreen() {}

  • Naming composable functions for widgets
@Composable
fun LoginButton() {}
@Composable
fun loginButton() {}
@Composable
fun renderLoginButton() {}

  • Naming preview functions with a Preview suffix
@Preview(showBackground = true)
@Composable
fun HomeScreenPreview() {}
@Preview(showBackground = true)
@Composable
fun HomeScreenpreview() {}

Naming @Composable functions

The names of composable functions that return values other than Unit must follow the standard Kotlin Coding Conventions for naming functions written in camelCase.

  • Naming @Composable functions that return values
@Composable
fun defaultStyle(): Style {
@Composable
fun DefaultStyle(): Style {

  • Naming @Composable functions that remember {} the objects they return

The names of composable factory functions that internally remember {} and return a mutable object must be prefixed with remember.

@Composable
fun rememberLoginState(): LoginState = remember {
  LoginState()
}
@Composable
fun createLoginState(): LoginState = remember {
  LoginState()
}

Ordering of annotations and Preview functions

  • @Preview must be placed on top of all other annotations.
  • @Composable must be located on top of class/function definition.
  • Preview functions must be added to the bottom of the files.
@Composable
fun LoginButton() {}

@Composable
fun LogoutButton() {}

...

@Preview(showBackground = true)
...
@Composable
fun LoginButtonPreview() {}

@Preview(showBackground = true)
...
@Composable
fun LogoutButtonPreview() {}

Detekt Rules

Configuration for Compose

In Jetpack Compose, the team follows the official Android API Guidelines to outline the patterns, best practices, and prescriptive style guidelines for writing idiomatic Jetpack Compose. However, some of these guidelines violate some of the default Detekt rules.

FunctionNaming

Using PascalCase for the function naming that violates the detekt rules:

@Composable
fun HomeScreen() {}
Configuration

Set ignoreAnnotated to [ 'Composable' ].

LongParameterList

In case of having many arguments in functions of Jetpack Compose. For example, the function for the UI widget:

@Composable
private fun HomeScreenContent(
    isFirstItemLoading: Boolean,
    isSecondItemLoading: Boolean,
    firstList: List<FirstItem>,
    secondList: List<SecondItem>,
    onFirstItemClick: (FirstItem) -> Unit = {},
    onSecondItemClick: (SecondItem) -> Unit = {},
    onRefresh: () -> Unit = {}
) {}
Configuration

Set ignoreDefaultParameters = true.

MagicNumber

In case of not specifying the named parameter. For example, when defining the code of color without a parameter name (i.e.,Color(color = 0xFFFFFFFF):

val White = Color(0xFFFFFFFF)
Configuration

Set ignorePropertyDeclaration = true.

TopLevelPropertyNaming

For the Property pattern the team also follows PascalCase from official Android API Guidelines , but for the Constant pattern, it’s still under team discussion.

val White = Color(0xFFFFFFFF)
Configuration

Set propertyPattern to [A-Za-z][A-Za-z0-9]*.

UnusedPrivateMember

Detekt will detect the composable preview functions that have been marked with @Preview as unused:

@Preview(showBackground = true)
@Composable
private fun HomeScreenPreview() {
    HomeScreenContent()
}
Configuration

Set ignoreAnnotated to [ 'Preview' ].

References