What You Will Build

A polished login/signup page with email and password fields, a password visibility toggle, form validation, and a switch between login and registration modes. This is the authentication screen pattern used in virtually every app that requires user accounts.

Why Login Screens Are the First Real Compose Test

A login page exercises text input handling, visual transformations, keyboard options, conditional UI, and button enable/disable logic. If you can build a solid login screen, you have the foundation for any form-based interface in Compose.

Key Compose Concepts

  • PasswordVisualTransformation for hiding password characters.
  • KeyboardOptions(keyboardType = KeyboardType.Email) for email-optimized keyboard.
  • Conditional button enabling with the enabled parameter.

State Setup

var email by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
var passwordVisible by remember { mutableStateOf(false) }
var isLogin by remember { mutableStateOf(true) }

The Password Field with Visibility Toggle

OutlinedTextField(
    value = password,
    onValueChange = { password = it },
    modifier = Modifier.fillMaxWidth(),
    label = { Text("Password") },
    leadingIcon = { Icon(Icons.Default.Lock, null) },
    trailingIcon = {
        IconButton(onClick = { passwordVisible = !passwordVisible }) {
            Icon(
                if (passwordVisible) Icons.Default.Visibility
                else Icons.Default.VisibilityOff,
                contentDescription = null
            )
        }
    },
    singleLine = true,
    visualTransformation = if (passwordVisible)
        VisualTransformation.None
    else PasswordVisualTransformation()
)

Login Button with Validation

Button(
    onClick = { /* Handle authentication */ },
    modifier = Modifier
        .fillMaxWidth()
        .height(50.dp),
    enabled = email.isNotBlank() && password.length >= 6
) {
    Text(
        if (isLogin) "Sign In" else "Sign Up",
        fontSize = 16.sp
    )
}

Spacer(Modifier.height(16.dp))

TextButton(onClick = { isLogin = !isLogin }) {
    Text(
        if (isLogin) "Don't have an account? Sign Up"
        else "Already have an account? Sign In"
    )
}

Tips and Pitfalls

  • Minimum password length of 6 is enforced with password.length >= 6 in the enabled check, giving real-time feedback.
  • VisualTransformation.None vs PasswordVisualTransformation() toggles between showing and hiding the password. The toggle icon also updates to indicate the current state.
  • Add verticalScroll to the Column modifier to prevent the soft keyboard from obscuring form fields on small screens.
  • KeyboardType.Email shows the @ symbol prominently on the keyboard, reducing friction for email entry.

Minimum SDK: API 24+ with Compose BOM 2024.01+

Get New Tutorials by Email

No spam. Just clear, practical breakdowns you can apply right away.

Enjoy this tutorial?

Get new practical tech tutorials in your inbox.