Javascript. Kotlin. Android. Java

Jetpack Compose: Login Screen

This post is going to go through making a simple login screen focusing mainly on a few key features. Not all of the code will be put in here as it would be too much.

You can however find all of the code here

Toggling password visibility

You've seen it everywhere. An icon or piece of clickable text that will turn your "*************" into a visible password.

This is achieved through the use of something clickable and a VisualTransormation which you can see more of here.

Declare a boolean piece of state to represent if the password is hidden or not. This will determine which icon is displayed. It also changes the VisualTransformation from None to type Password which is probably the only time you might use VisualTransformation ever.

    fun PasswordInput(...) {
        var isPasswordHidden by remember {
            trailingIcon = {
                IconButton(onClick = {
                    isPasswordHidden = !isPasswordHidden
                }) {
                    if(isPasswordHidden) {
                        Icon("Show password")
                    } else {
                        Icon("Show password")
        visualTransformation = if(isPasswordHidden) {
        } else VisualTransformation.None)

Password requirements

Many sites when you go to create an account either require that the password meet certain requirements or they might indicate a "Stength" indicator which is basically the same thing it just doesn't explicitly say what is strong.

Here we are going to have 3 mandatory password requirements: 8 characters long, a number and a capital letter.

What we need...

To make this work we need a few things in the code:

  • To define the requirements
  • To store those requirements in our state
  • To update the stored requirements as we achieve them
The requirements
Updated state
Updating the state
    enum class PasswordRequirements(@StringRes val label: Int){
    data class PasswordFieldState(
        val password: String? = null,
        val passwordRequirements: List<PasswordRequirements> = emptyList())
    private fun updatePassword(password: String) {
        val requirements = mutableListOf<PasswordRequirements>()
        if (password.length > 7) {
        if (password.any { it.isUpperCase() }) {
        if (password.any { it.isDigit() }) {

        uiState.value = uiState.value.copy(
            password = password,
            passwordRequirements = requirements.toList())

With all that in place, all that is left is to handle that in our Composable and update the text color as necessary.

    fun PasswordRequirements(..
        satisfiedRequirements: List<PasswordRequirements>) {

        Column(..) {
            PasswordRequirements.values().forEach { req ->
                    satisfied = satisfiedRequirements.contains(req))

    fun RequirementEntry(..
        satisfied: Boolean) {

        val tint = if(satisfied) {
        } else

        Row(..) {
                imageVector = Icons.Default.Check,
                tint = tint

                text = label,
                color = tint

Again, you can find all of the code here

The following course gave me a great primer into Compose. Look up Joe's twitter too.