Code A Program
Build a Responsive Login & Signup Form with HTML, CSS & JavaScript
Published on August 24, 2025

Build a Responsive Login & Signup Form with HTML, CSS & JavaScript

Every great website or app needs a welcoming front door. That's your authentication form. A clean, modern, and intuitive form not only improves the user experience but also builds trust. In this tutorial, we'll build a beautiful, responsive Login and Signup form from scratch using only HTML, CSS, and JavaScript.

By the end, you'll have a fully functional form that's ready to be the gateway to your next big project! 🚀


✅ What We'll Build

Here’s a sneak peek at the features you'll be implementing:

  • A Sleek Card Layout: A centered form that "floats" on a beautiful gradient background.

  • Two Forms, One View: A Login form (Email + Password) and a Signup form (Email + Password + Confirm Password).

  • Interactive Toggling: A smooth way for users to switch between the Login and Signup views.

  • Real-time Validation: JavaScript-powered checks to ensure users enter valid information.

  • Modern Styling: Subtle hover effects and transitions for a professional feel.

  • Fully Responsive: Looks fantastic on desktops, tablets, and mobile phones.

Ready to dive in? Let's get started!


📂 Step 1: Setting Up Your Project

First things first, let's get our workspace ready. It's super simple!

  1. Create a new folder and name it something like auth-form-project.

  2. Inside that folder, create a single file: index.html.

That's it! We will write all our HTML, CSS, and JavaScript in this one file to keep things straightforward.

project/
└── index.html

📄 Step 2: Building the HTML Structure

The foundation of our form is the HTML. We need to structure it logically so we can style it with CSS and add functionality with JavaScript later. We'll create a main container that holds two forms: one for logging in and one for signing up.

Open your index.html file and add the following code.

HTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login & Signup Form</title>
</head>
<body>
  <div class="container" id="form-container">
    <form id="login-form">
      <h2>Login</h2>
      <div class="form-group">
        <label for="login-email">Email</label>
        <input type="email" id="login-email" placeholder="Enter your email">
        <div class="error" id="login-email-error"></div>
      </div>
      <div class="form-group">
        <label for="login-password">Password</label>
        <input type="password" id="login-password" placeholder="Enter your password">
        <div class="error" id="login-password-error"></div>
      </div>
      <button type="submit">Login</button>
      <div class="toggle-text">Don’t have an account? <a id="show-signup">Sign up</a></div>
    </form>

    <form id="signup-form" style="display: none;">
      <h2>Sign Up</h2>
      <div class="form-group">
        <label for="signup-email">Email</label>
        <input type="email" id="signup-email" placeholder="Enter your email">
        <div class="error" id="signup-email-error"></div>
      </div>
      <div class="form-group">
        <label for="signup-password">Password</label>
        <input type="password" id="signup-password" placeholder="Enter your password">
        <div class="error" id="signup-password-error"></div>
      </div>
      <div class="form-group">
        <label for="signup-confirm-password">Confirm Password</label>
        <input type="password" id="signup-confirm-password" placeholder="Confirm your password">
        <div class="error" id="signup-confirm-error"></div>
      </div>
      <button type="submit">Sign Up</button>
      <div class="toggle-text">Already have an account? <a id="show-login">Login</a></div>
    </form>
  </div>
</body>
</html>

Breaking Down the HTML:

  • <div class="container">: This is the main wrapper for our forms. It will act as the centered card.

  • <form>: We have two forms, one with id="login-form" and another with id="signup-form".

  • style="display: none;": The signup form is hidden by default. We'll use JavaScript to show it when the user clicks the "Sign up" link.

  • <div class="form-group">: Each of these divs groups a label, an input field, and an error message placeholder together for easy styling.

  • <label for="...">: Using the for attribute links the label to its corresponding input (by id). This is great for accessibility—clicking the label now focuses the input field.

  • <div class="error">: These empty divs are crucial. We'll use JavaScript to inject validation error messages here.

  • <div class="toggle-text">: This contains the link (<a>) that will allow users to switch between the login and signup forms.


🎨 Step 3: Adding Modern CSS Styling

With the structure in place, it's time to make our form look amazing! Let's add the CSS within a <style> tag in the <head> section of your index.html file.

HTML
<head>
    <style>
        /* CSS code goes here */
    </style>
</head>

Add the following CSS inside the <style> tag.

CSS
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: "Segoe UI", sans-serif;
}

body {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  background: linear-gradient(135deg, #6a11cb, #2575fc);
}

.container {
  background: #fff;
  padding: 2rem;
  border-radius: 12px;
  width: 100%;
  max-width: 400px;
  box-shadow: 0 8px 20px rgba(0,0,0,0.15);
  margin: 0 1rem; /* Added margin for small screens */
}

h2 {
  text-align: center;
  margin-bottom: 1.5rem;
  color: #333;
}

.form-group {
  margin-bottom: 1rem;
}

.form-group label {
  display: block;
  margin-bottom: 0.3rem;
  color: #444;
  font-size: 14px;
}

.form-group input {
  width: 100%;
  padding: 0.75rem;
  border: 1px solid #ccc;
  border-radius: 8px;
  outline: none;
  transition: border-color 0.3s;
}

.form-group input:focus {
  border-color: #2575fc;
}

.error {
  color: red;
  font-size: 12px;
  min-height: 1em; /* Prevents layout shifts */
  margin-top: 0.3rem;
}

button {
  width: 100%;
  padding: 0.75rem;
  border: none;
  border-radius: 8px;
  background: #2575fc;
  color: #fff;
  font-size: 16px;
  cursor: pointer;
  transition: background 0.3s;
}

button:hover {
  background: #1a5bd7;
}

.toggle-text {
  margin-top: 1rem;
  text-align: center;
  font-size: 14px;
}

.toggle-text a {
  color: #2575fc;
  cursor: pointer;
  text-decoration: none;
  font-weight: 600;
}

/* Responsive Design */
@media (max-width: 450px) {
  .container {
    padding: 1.5rem;
  }
}

Styling Explained:

  • box-sizing: border-box;: This universal rule makes layout math much more intuitive by including padding and border in an element's total width and height.

  • body Styling: We use Flexbox (display: flex) to easily center our form container both vertically (align-items: center) and horizontally (justify-content: center). The height: 100vh ensures the body takes up the full viewport height. The linear-gradient provides that cool background effect.

  • .container Card: We give it a white background, padding, rounded corners (border-radius), and a subtle box-shadow to make it lift off the page. max-width ensures it doesn't get too wide on large screens.

  • input:focus: This pseudo-class highlights the input field with a blue border when a user clicks on it, improving user experience.

  • Transitions: The subtle transition on the input's border-color and the button's background provides a smooth visual feedback on user interaction.

  • @media Query: This is the key to responsiveness. It says, "On screens 450px wide or smaller, apply these adjusted styles." Here, we reduce the padding to give the form more space on mobile devices.


⚡ Step 4: Adding JavaScript for Functionality

Now for the magic! We'll use JavaScript to handle two things:

  1. Toggling between the Login and Signup forms.

  2. Validating user input to prevent empty or invalid submissions.

Add a <script> tag just before the closing </body> tag and place the following JavaScript code inside it.

HTML

HTML
<script>
    // JavaScript code goes here
</script>
</body>
JavaScript
const loginForm = document.getElementById("login-form");
const signupForm = document.getElementById("signup-form");
const showSignup = document.getElementById("show-signup");
const showLogin = document.getElementById("show-login");

// --- TOGGLE BETWEEN FORMS ---
showSignup.addEventListener("click", (e) => {
  e.preventDefault(); // Prevent link from navigating
  loginForm.style.display = "none";
  signupForm.style.display = "block";
});

showLogin.addEventListener("click", (e) => {
  e.preventDefault(); // Prevent link from navigating
  signupForm.style.display = "none";
  loginForm.style.display = "block";
});

// --- HELPER FUNCTION FOR EMAIL VALIDATION ---
function isValidEmail(email) {
  const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return regex.test(email);
}

// --- ERROR DISPLAY HELPER ---
function displayError(elementId, message) {
  const errorElement = document.getElementById(elementId);
  errorElement.textContent = message;
}

function clearError(elementId) {
    document.getElementById(elementId).textContent = "";
}

// --- LOGIN FORM VALIDATION ---
loginForm.addEventListener("submit", function(e) {
  e.preventDefault(); // Stop the form from submitting the traditional way
  let valid = true;

  const email = document.getElementById("login-email").value.trim();
  const password = document.getElementById("login-password").value.trim();

  // Validate Email
  if (!email) {
    displayError("login-email-error", "Email is required");
    valid = false;
  } else if (!isValidEmail(email)) {
    displayError("login-email-error", "Please enter a valid email address");
    valid = false;
  } else {
    clearError("login-email-error");
  }

  // Validate Password
  if (!password) {
    displayError("login-password-error", "Password is required");
    valid = false;
  } else {
    clearError("login-password-error");
  }

  if (valid) {
    alert("Login successful!");
    loginForm.reset();
  }
});

// --- SIGNUP FORM VALIDATION ---
signupForm.addEventListener("submit", function(e) {
  e.preventDefault();
  let valid = true;

  const email = document.getElementById("signup-email").value.trim();
  const password = document.getElementById("signup-password").value.trim();
  const confirmPassword = document.getElementById("signup-confirm-password").value.trim();
  
  // Validate Email
  if (!email) {
    displayError("signup-email-error", "Email is required");
    valid = false;
  } else if (!isValidEmail(email)) {
    displayError("signup-email-error", "Please enter a valid email address");
    valid = false;
  } else {
    clearError("signup-email-error");
  }

  // Validate Password
  if (!password) {
    displayError("signup-password-error", "Password is required");
    valid = false;
  } else if (password.length < 6) {
    displayError("signup-password-error", "Password must be at least 6 characters long");
    valid = false;
  } else {
    clearError("signup-password-error");
  }

  // Validate Confirm Password
  if (confirmPassword !== password) {
    displayError("signup-confirm-error", "Passwords do not match");
    valid = false;
  } else {
    clearError("signup-confirm-error");
  }
  
  if (valid) {
    alert("Signup successful!");
    signupForm.reset();
  }
});

JavaScript Explained:

  • Element Selection: We start by grabbing all the important HTML elements (the forms and the toggle links) using document.getElementById and storing them in constants.

  • addEventListener: This is the core of interactivity. We listen for a "click" on our toggle links and a "submit" on our forms.

  • Form Toggling: When a toggle link is clicked, we simply hide one form (style.display = "none") and show the other (style.display = "block").

  • e.preventDefault(): This is extremely important. By default, clicking a link tries to navigate away, and submitting a form reloads the page. This command stops that default behavior, allowing our script to take control.

  • Validation Logic:

    • We use a valid flag that starts as true and is set to false if any validation check fails.

    • .trim() is used to remove any accidental whitespace from the beginning or end of the user's input.

    • We check for empty fields, a valid email format (using a Regular Expression or RegEx), a minimum password length, and whether the confirmed password matches.

    • Based on the checks, we use our helper functions to either display an error message in the corresponding .error div or clear it.

  • Success!: If, after all the checks, the valid flag is still true, we show a success alert() and use form.reset() to clear the input fields.


🎉 Final Result

Congratulations! You have successfully built a beautiful and functional Login & Signup form. You now have:

  • A centered form that opens with the Login view.

  • A seamless toggle to switch to the Signup form.

  • Client-side validation that provides instant feedback to the user.

  • A fully responsive design that works across all devices.

🚀 Next Steps

This project is a fantastic foundation. Here are a few ideas to take it to the next level:

  • Add a "Show/Hide Password" Toggle: Implement an eye icon (👁️) that lets users see the password they're typing.

  • Connect to a Backend: Use the fetch() API to send the form data to a real backend server (like Node.js, Python, or PHP) for actual user authentication.

  • Store Login Sessions: Use localStorage or sessionStorage to keep a user logged in after they've successfully authenticated.

  • Add More Complex Password Rules: Enhance your validation to require uppercase letters, numbers, or special characters in the password.

Happy coding!

Share: