In today’s web development landscape, providing a smooth and intuitive user experience is essential, especially when it comes to something as important as user authentication. In this post, we’ll walk through the process of building a clean, responsive login and registration form. We’ll cover everything from the basic HTML structure to the subtle design touches that make your forms feel modern and user-friendly. Let’s dive in!
Getting Started: The HTML Structure
We begin with a basic HTML5 structure that sets the stage for our login and register forms. Here’s a brief look at the code snippet that forms our foundation:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- BOXICONS --> <link href='https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css' rel='stylesheet'> <!-- CSS --> <link rel="stylesheet" href="css/style.css"> <title>Login & Register | Ludiflex</title> </head> <body> <div class="wrapper"> <div class="form-header"> <div class="titles"> <div class="title-login">Login</div> <div class="title-register">Register</div> </div> </div> <!-- LOGIN FORM --> <form action="#" class="login-form" autocomplete="off"> <!-- Login form inputs --> </form> <!-- REGISTER FORM --> <form action="#" class="register-form" autocomplete="off"> <!-- Register form inputs --> </form> </div> <script src="js/script.js"></script> </body> </html>
Key Points in Our HTML:
- Semantic Markup: The use of semantic HTML elements such as
<form>
and<input>
helps improve accessibility and maintainability. - Responsive Design: The meta viewport tag ensures our forms render well on different devices.
- External Libraries: We link to Boxicons for attractive iconography, which enhances the overall user experience.
- Styles and Scripts: External CSS (
css/style.css
) and JavaScript (js/script.js
) files allow us to keep our HTML clean and our code modular.
Crafting the Login Form
Let’s take a closer look at the login form. Notice how each input field is wrapped in an input-box
div that includes not only the <input>
element but also a <label>
and an icon:
<!-- LOGIN FORM --> <form action="#" class="login-form" autocomplete="off"> <div class="input-box"> <input type="text" class="input-field" id="log-email" required> <label for="log-email" class="label">Email</label> <i class='bx bx-envelope icon'></i> </div> <div class="input-box"> <input type="password" class="input-field" id="log-pass" required> <label for="log-pass" class="label">Password</label> <i class='bx bx-lock-alt icon'></i> </div> <div class="form-cols"> <div class="col-1"></div> <div class="col-2"> <a href="#">Forgot password?</a> </div> </div> <div class="input-box"> <button class="btn-submit" id="SignInBtn">Sign In <i class='bx bx-log-in'></i></button> </div> <div class="switch-form"> <span>Don't have an account? <a href="#" onclick="registerFunction()">Register</a></span> </div> </form>
Highlights:
- Floating Labels: The labels for each input are placed after the input element, which can be styled to create a floating label effect. This not only looks modern but also improves usability.
- Icon Usage: Using icons (via Boxicons) next to each input field adds a visual cue that helps users quickly understand what each field represents.
- User Flow: A “Forgot password?” link is included, and there’s an easy transition to the registration form with a call-to-action at the bottom.
Building the Register Form
The registration form follows a similar structure but includes a few additional elements to accommodate the registration process:
<!-- REGISTER FORM --> <form action="#" class="register-form" autocomplete="off"> <div class="input-box"> <input type="text" class="input-field" id="reg-name" required> <label for="reg-name" class="label">Username</label> <i class='bx bx-user icon'></i> </div> <div class="input-box"> <input type="text" class="input-field" id="reg-email" required> <label for="reg-email" class="label">Email</label> <i class='bx bx-envelope icon'></i> </div> <div class="input-box"> <input type="password" class="input-field" id="reg-pass" required> <label for="reg-pass" class="label">Password</label> <i class='bx bx-lock-alt icon'></i> </div> <div class="form-cols"> <div class="col-1"> <input type="checkbox" id="agree"> <label for="agree"> I agree to terms & conditions</label> </div> <div class="col-2"></div> </div> <div class="input-box"> <button class="btn-submit" id="SignUpBtn">Sign Up <i class='bx bx-user-plus' ></i></button> </div> <div class="switch-form"> <span>Already have an account? <a href="#" onclick="loginFunction()">Login</a></span> </div> </form>
Highlights:
- Additional Fields: The registration form includes an extra field for the username, which is often required during sign-up.
- Terms and Conditions: There’s a checkbox for users to agree to the terms and conditions. This small detail is crucial for compliance and user trust.
- Smooth Navigation: Just like the login form, there’s a clear call-to-action that encourages users who already have an account to log in, creating a seamless transition between the two forms.
Enhancing the Experience with CSS and JavaScript
CSS Styling
While our HTML provides the structure, CSS brings our forms to life. In your css/style.css
file, you can define styles for the wrapper, forms, input fields, and buttons. Some useful CSS techniques include:
- Flexbox or Grid: Use these layout models to center your forms and ensure they’re responsive.
- Transitions and Animations: Smooth transitions on focus or hover states for inputs and buttons improve the user experience.
- Responsive Design: Media queries help adapt the form layout to various screen sizes, ensuring usability on mobile devices.
/* IMPORT FONT */ @import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap'); /* COLOR VARIABLES */ :root { --primary-color: #0D1936; --secondary-color: #535354; --background-color: #EFEFEF; --shadow-color: rgba(0, 0, 0, 0.1); --white-color: #FFF; --black-color: #000; --input-border-color: #E3E4E6; --transition-3s: 0.3s; } /* GLOBAL STYLES */ *{ margin: 0; padding: 0; box-sizing: border-box; font-family: 'Poppins', sans-serif; } /* REUSABLE ELEMENTS */ a{ text-decoration: none; color: var(--black-color); transition: var(--transition-3s); } a:hover{ text-decoration: underline; } body{ display: flex; justify-content: center; align-items: center; height: 100vh; background-color: var(--background-color); } /* WRAPPER */ .wrapper{ position: relative; width: 430px; height: 500px; background-color: var(--white-color); border-radius: 15px; padding: 120px 32px 64px; border: 1px solid var(--primary-color); box-shadow: 0 8px 15px var(--shadow-color); transition: var(--transition-3s); overflow: hidden; } /* FORM HEADER */ .form-header{ position: absolute; top: 0; left: 50%; transform: translateX(-50%); display: flex; align-items: center; justify-content: center; width: 140px; height: 70px; background-color: var(--primary-color); border-radius: 0 0 20px 20px; } .form-header::before, .form-header::after{ content: ""; position: absolute; top: 0; width: 30px; height: 30px; } .form-header::before{ left: -30px; border-top-right-radius: 50%; box-shadow: 15px 0 0 var(--primary-color); } .form-header::after{ right: -30px; border-top-left-radius: 50%; box-shadow: -15px 0 0 var(--primary-color); } /* TITLES */ .titles{ position: relative; } .title-login, .title-register{ position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); color: var(--white-color); font-size: 24px; transition: var(--transition-3s); } .title-register{ top: 50px; } /* FORMS */ .login-form, .register-form{ position: absolute; left: 50%; transform: translateX(-50%); width: 85%; transition: var(--transition-3s); } .register-form{ left: 150%; } /* INPUT FIELDS */ .input-box{ position: relative; display: flex; flex-direction: column; margin: 20px 0; } .input-field{ width: 100%; height: 55px; font-size: 16px; background: transparent; color: var(--black-color); padding: 0 20px; border: 1px solid var(--input-border-color); border-radius: 30px; outline: none; transition: var(--transition-3s); } .input-field:focus{ border: 1px solid var(--primary-color); } .label{ position: absolute; top: 50%; left: 20px; transform: translateY(-50%); color: var(--secondary-color); transition: 0.2s; cursor: text; } .input-field:focus ~ .label, .input-field:valid ~ .label{ top: 0; font-size: 14px; background-color: var(--white-color); color: var(--primary-color); padding: 0 10px; } .input-field:valid ~ .label{ color: var(--secondary-color); } .icon{ position: absolute; top: 50%; right: 25px; transform: translateY(-50%); font-size: 20px; color: var(--secondary-color); } /* FORGOT PASSWORD & TERMS AND CONDITIONS */ .form-cols{ display: flex; justify-content: space-between; font-size: 14px; } .col-1{ display: flex; align-items: center; gap: 6px; } /* SUBMIT BUTTON */ .btn-submit{ display: flex; align-items: center; justify-content: center; gap: 10px; width: 100%; height: 50px; background-color: var(--primary-color); color: var(--white-color); font-size: 16px; font-weight: 500; border: none; border-radius: 30px; cursor: pointer; transition: var(--transition-3s); } .btn-submit:hover{ gap: 15px; } .btn-submit i{ font-size: 20px; } /* SWITCH FORM */ .switch-form{ text-align: center; } .switch-form a{ font-weight: 500; } /* RESPONSIVE STYLES */ @media only screen and (max-width: 564px){ .wrapper{ margin: 20px; } }
JavaScript Interactivity
In the snippet above, you might have noticed functions like registerFunction()
and loginFunction()
. These functions (defined in your js/script.js
file) handle the transition between the login and registration forms. A simple implementation could involve toggling the visibility of each form:
const loginForm = document.querySelector(".login-form"); const registerForm = document.querySelector(".register-form"); const wrapper = document.querySelector(".wrapper"); const loginTitle = document.querySelector(".title-login"); const registerTitle = document.querySelector(".title-register"); const signUpBtn = document.querySelector("#SignUpBtn"); const signInBtn = document.querySelector("#SignInBtn"); function loginFunction(){ loginForm.style.left = "50%"; loginForm.style.opacity = 1; registerForm.style.left = "150%"; registerForm.style.opacity = 0; wrapper.style.height = "500px"; loginTitle.style.top = "50%"; loginTitle.style.opacity = 1; registerTitle.style.top = "50px"; registerTitle.style.opacity = 0; } function registerFunction(){ loginForm.style.left = "-50%"; loginForm.style.opacity = 0; registerForm.style.left = "50%"; registerForm.style.opacity = 1; wrapper.style.height = "580px"; loginTitle.style.top = "-60px"; loginTitle.style.opacity = 0; registerTitle.style.top = "50%"; registerTitle.style.opacity = 1; }