Android Authentication UI in Jetpack Compose: Modern Login Screen (Full Code Explained)

Android Authentication UI: Build a Modern Login Screen Using Jetpack Compose

A well-designed login screen improves trust and makes your app feel professional. In this tutorial, you’ll learn how a modern Authentication UI is built using Jetpack Compose—complete with a gradient background, decorative circles, a centered card, email/password fields, “Remember me”, “Forgot password”, a Sign In button, and social login icons.



What This Login Screen Includes

  • Full-screen gradient background
  • Top-left back button inside a circular container
  • Decorative circles for a clean modern look
  • Rounded Card with elevation (main login form)
  • Email and password input using OutlinedTextField
  • Remember me checkbox + forgot password link
  • Primary Sign In button
  • Social login buttons: Facebook, Twitter, Google, Apple
  • Sign up footer link


Dependencies Required

Add these to your build.gradle.kts (Module: app):

dependencies {
    implementation("androidx.compose.ui:ui:1.5.4")
    implementation("androidx.compose.material3:material3:1.1.2")
    implementation("androidx.compose.material:material-icons-extended:1.5.4")
}


1) State in Jetpack Compose (Email, Password, Remember Me)

Your screen stores UI state using remember and mutableStateOf():

var email by remember { mutableStateOf("newkingsapps@gmil.com") }
var password by remember { mutableStateOf("password") }
var rememberMe by remember { mutableStateOf(true) }

When the user types or toggles the checkbox, the state updates and Compose automatically redraws the affected UI. For production apps, it’s common to move this state into a ViewModel, but keeping it inside the composable is perfectly fine for UI demos and prototypes.


2) Root Layout + Gradient Background

The root container is a Box, which is ideal when you want to stack UI elements (background → decorations → card) on top of each other.

Box(
  modifier = Modifier
    .fillMaxSize()
    .background(
      brush = Brush.verticalGradient(
        colors = listOf(Color(0xFF7B8CDE), Color(0xFFB8C5E8))
      )
    )
)

The Brush.verticalGradient() creates a smooth modern background without needing image assets, which keeps the UI lightweight and scalable across screen sizes.


3) Back Button (Top-Left)

The back button uses an IconButton with a circular shape and a solid background color, placed using align(Alignment.TopStart):

IconButton(
  onClick = { /* Handle back */ },
  modifier = Modifier
    .padding(16.dp)
    .size(48.dp)
    .clip(CircleShape)
    .background(Color(0xFF4A5F8F))
    .align(Alignment.TopStart)
)

In a real app, you can connect this to Navigation (for example: navController.popBackStack()) or your activity’s back press handling.


4) Decorative Circles (Modern UI Styling)

The three circle boxes are purely decorative. They add depth and give the login screen a premium feel. Each circle uses:

  • clip(CircleShape) to become a perfect circle
  • size() to define the diameter
  • offset() to place it creatively
  • background(color.copy(alpha = ...)) for transparency

This technique is popular because it looks stylish while keeping the UI fast (no big images required).


5) Login Card (Main Content)

The login form is placed inside a Material 3 Card centered on the screen. The rounded corners and elevation help separate it from the gradient background.

Card(
  modifier = Modifier
    .fillMaxWidth()
    .padding(horizontal = 24.dp)
    .align(Alignment.Center),
  shape = RoundedCornerShape(24.dp),
  colors = CardDefaults.cardColors(containerColor = Color.White),
  elevation = CardDefaults.cardElevation(defaultElevation = 8.dp)
)


6) Email Field (OutlinedTextField)

The email input is implemented using OutlinedTextField. The important part is two-way binding: the field reads from email and writes back using onValueChange.

OutlinedTextField(
  value = email,
  onValueChange = { email = it },
  modifier = Modifier.fillMaxWidth(),
  colors = OutlinedTextFieldDefaults.colors(
    focusedBorderColor = Color(0xFF5B6FBD),
    unfocusedBorderColor = Color.LightGray
  ),
  shape = RoundedCornerShape(8.dp)
)

Tip: For a real login, consider adding keyboardOptions (email keyboard) and singleLine = true to improve UX.


7) Password Field (Hidden Input)

The password field is similar to email, but it uses PasswordVisualTransformation() to hide the typed characters.

OutlinedTextField(
  value = password,
  onValueChange = { password = it },
  modifier = Modifier.fillMaxWidth(),
  visualTransformation = PasswordVisualTransformation(),
  ...
)

You can later add a “show/hide password” toggle with a trailing icon for even better usability.


8) Remember Me + Forgot Password

This row uses Arrangement.SpaceBetween to push the checkbox area to the left and the “Forgot password?” action to the right.

Row(
  modifier = Modifier.fillMaxWidth(),
  horizontalArrangement = Arrangement.SpaceBetween,
  verticalAlignment = Alignment.CenterVertically
)

The checkbox is connected to rememberMe state, and the button can open a reset-password flow or a new screen.


9) Sign In Button (Primary CTA)

The Sign In button is full width, tall, and rounded—great for thumb reach and modern design.

Button(
  onClick = { /* Handle sign in */ },
  modifier = Modifier
    .fillMaxWidth()
    .height(56.dp),
  colors = ButtonDefaults.buttonColors(containerColor = Color(0xFF5B6FBD)),
  shape = RoundedCornerShape(12.dp)
)


10) Social Login Buttons (Icons)

Social buttons are displayed using a row with Arrangement.SpaceEvenly. Each icon is loaded from drawable resources using painterResource().

To preserve original brand colors (Google/Facebook/etc.), you used tint = Color.Unspecified, which is the right approach when your icons are already colored.


11) Sign Up Footer

The final row shows a friendly call to action: “Don’t have an account? Sign up”. The TextButton makes “Sign up” clickable without making the UI feel heavy.


Next Steps (Optional Improvements)

  • Add validation (email format, password length)
  • Add loading state (disable Sign In button + show progress)
  • Move state into a ViewModel for production architecture
  • Use Navigation Compose for back, sign up, and forgot password screens
  • Localize strings using stringResource()


Jetpack Compose LoginScreen() Full Source Code

@Composable
fun LoginScreen() {
    var email by remember { mutableStateOf("newkingsapps@gmail.com") }
    var password by remember { mutableStateOf("password") }
    var rememberMe by remember { mutableStateOf(true) }

    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(
                brush = Brush.verticalGradient(
                    colors = listOf(
                        Color(0xFF7B8CDE),
                        Color(0xFFB8C5E8)
                    )
                )
            )
    ) {
        // Back Button
        IconButton(
            onClick = { /* Handle back */ },
            modifier = Modifier
                .padding(16.dp)
                .size(48.dp)
                .clip(CircleShape)
                .background(Color(0xFF4A5F8F))
                .align(Alignment.TopStart)
        ) {
            Icon(
                imageVector = Icons.Default.ArrowBack,
                contentDescription = "Back",
                tint = Color.White
            )
        }

        // Decorative Circles
        Box(
            modifier = Modifier
                .fillMaxWidth()
                .height(300.dp)
                .align(Alignment.TopCenter)
        ) {
            // Large circle
            Box(
                modifier = Modifier
                    .size(200.dp)
                    .offset(y = 50.dp, x = 100.dp)
                    .clip(CircleShape)
                    .background(Color(0xFF8B9BD9).copy(alpha = 0.5f))
                    .align(Alignment.TopEnd)
            )

            // Medium circle
            Box(
                modifier = Modifier
                    .size(120.dp)
                    .offset(y = 120.dp, x = (-20).dp)
                    .clip(CircleShape)
                    .background(Color.White.copy(alpha = 0.3f))
                    .align(Alignment.Center)
            )

            // Small circle
            Box(
                modifier = Modifier
                    .size(80.dp)
                    .offset(y = 150.dp, x = 50.dp)
                    .clip(CircleShape)
                    .background(Color.White.copy(alpha = 0.8f))
                    .align(Alignment.CenterEnd)
            )
        }

        // Login Card
        Card(
            modifier = Modifier
                .fillMaxWidth()
                .padding(horizontal = 24.dp)
                .align(Alignment.Center),
            shape = RoundedCornerShape(24.dp),
            colors = CardDefaults.cardColors(
                containerColor = Color.White
            ),
            elevation = CardDefaults.cardElevation(defaultElevation = 8.dp)
        ) {
            Column(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(32.dp),
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                // Welcome Text
                Text(
                    text = "Welcome back",
                    fontSize = 24.sp,
                    fontWeight = FontWeight.Bold,
                    color = Color(0xFF4A5F8F)
                )

                Spacer(modifier = Modifier.height(32.dp))

                // Email Field
                Column(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalAlignment = Alignment.Start
                ) {
                    Text(
                        text = "Email",
                        fontSize = 14.sp,
                        color = Color.Gray,
                        modifier = Modifier.padding(bottom = 8.dp)
                    )
                    OutlinedTextField(
                        value = email,
                        onValueChange = { email = it },
                        modifier = Modifier.fillMaxWidth(),
                        colors = OutlinedTextFieldDefaults.colors(
                            focusedBorderColor = Color(0xFF5B6FBD),
                            unfocusedBorderColor = Color.LightGray
                        ),
                        shape = RoundedCornerShape(8.dp)
                    )
                }

                Spacer(modifier = Modifier.height(16.dp))

                // Password Field
                Column(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalAlignment = Alignment.Start
                ) {
                    Text(
                        text = "Password",
                        fontSize = 14.sp,
                        color = Color.Gray,
                        modifier = Modifier.padding(bottom = 8.dp)
                    )
                    OutlinedTextField(
                        value = password,
                        onValueChange = { password = it },
                        modifier = Modifier.fillMaxWidth(),
                        visualTransformation = PasswordVisualTransformation(),
                        colors = OutlinedTextFieldDefaults.colors(
                            focusedBorderColor = Color(0xFF5B6FBD),
                            unfocusedBorderColor = Color.LightGray
                        ),
                        shape = RoundedCornerShape(8.dp)
                    )
                }

                Spacer(modifier = Modifier.height(16.dp))

                // Remember Me & Forgot Password
                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.SpaceBetween,
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    Row(
                        verticalAlignment = Alignment.CenterVertically
                    ) {
                        Checkbox(
                            checked = rememberMe,
                            onCheckedChange = { rememberMe = it },
                            colors = CheckboxDefaults.colors(
                                checkedColor = Color(0xFF5B6FBD)
                            )
                        )
                        Text(
                            text = "Remember me",
                            fontSize = 14.sp,
                            color = Color.Gray
                        )
                    }

                    TextButton(onClick = { /* Handle forgot password */ }) {
                        Text(
                            text = "Forgot password?",
                            fontSize = 14.sp,
                            color = Color(0xFF5B6FBD)
                        )
                    }
                }

                Spacer(modifier = Modifier.height(24.dp))

                // Sign In Button
                Button(
                    onClick = { /* Handle sign in */ },
                    modifier = Modifier
                        .fillMaxWidth()
                        .height(56.dp),
                    colors = ButtonDefaults.buttonColors(
                        containerColor = Color(0xFF5B6FBD)
                    ),
                    shape = RoundedCornerShape(12.dp)
                ) {
                    Text(
                        text = "Sign In",
                        fontSize = 16.sp,
                        fontWeight = FontWeight.Bold
                    )
                }

                Spacer(modifier = Modifier.height(24.dp))

                // Sign in with
                Text(
                    text = "Sign in with",
                    fontSize = 14.sp,
                    color = Color.Gray
                )

                Spacer(modifier = Modifier.height(16.dp))

                // Social Login Icons
                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.SpaceEvenly
                ) {
                    // Facebook
                    IconButton(
                        onClick = { /* Handle Facebook login */ },
                        modifier = Modifier
                            .size(48.dp)
                            .clip(CircleShape)
                    ) {
                        Icon(
                            painter = painterResource(id = R.drawable.ic_facebook),
                            contentDescription = "Facebook",
                            tint = Color.Unspecified
                        )
                    }

                    // Twitter
                    IconButton(
                        onClick = { /* Handle Twitter login */ },
                        modifier = Modifier
                            .size(48.dp)
                            .clip(CircleShape)
                    ) {
                        Icon(
                            painter = painterResource(id = R.drawable.ic_twitter),
                            contentDescription = "Twitter",
                            tint = Color.Unspecified
                        )
                    }

                    // Google
                    IconButton(
                        onClick = { /* Handle Google login */ },
                        modifier = Modifier
                            .size(48.dp)
                            .clip(CircleShape)
                    ) {
                        Icon(
                            painter = painterResource(id = R.drawable.ic_google),
                            contentDescription = "Google",
                            tint = Color.Unspecified
                        )
                    }

                    // Apple
                    IconButton(
                        onClick = { /* Handle Apple login */ },
                        modifier = Modifier
                            .size(48.dp)
                            .clip(CircleShape)
                    ) {
                        Icon(
                            painter = painterResource(id = R.drawable.ic_apple),
                            contentDescription = "Apple",
                            tint = Color.Black
                        )
                    }
                }

                Spacer(modifier = Modifier.height(24.dp))

                // Sign Up Text
                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.Center,
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    Text(
                        text = "Don't have an account? ",
                        fontSize = 14.sp,
                        color = Color.Gray
                    )
                    TextButton(
                        onClick = { /* Handle sign up */ },
                        contentPadding = PaddingValues(0.dp)
                    ) {
                        Text(
                            text = "Sign up",
                            fontSize = 14.sp,
                            color = Color(0xFF5B6FBD),
                            fontWeight = FontWeight.Bold
                        )
                    }
                }
            }
        }
    }
}


FAQ

Is Jetpack Compose good for login screens?

Yes. Compose makes it easy to build responsive UIs with less code, and state handling becomes straightforward using composable state or ViewModel state.

How do I keep social login icons in original colors?

Use colored PNG/SVG assets and set tint = Color.Unspecified so Compose doesn’t recolor them.

Can I reuse this UI for a register screen?

Yes. You can reuse the Card layout and fields, then add extra inputs like username, confirm password, and terms acceptance checkbox.




Post a Comment

0 Comments