CodingLad
css

Sliding Sign-In and Sign-Up Component with Tailwind CSS

Sliding Sign-In and Sign-Up Component with Tailwind CSS
0 views
11 min read
#css

Sliding Sign-In and Sign-Up Component with Tailwind CSS

In this tutorial, we'll explore how to create a sliding sign-In and sign-up component with Tailwind CSS. This component will provide a smooth and interactive user experience, allowing users to toggle between sign-in and sign-up forms seamlessly. We'll leverage the power of React and Tailwind CSS to create a visually appealing and responsive design.

Features of Our Sliding Authentication Component

Sliding Sign-In and Sign-Up Component
  1. Toggle between Sign In and Sign Up seamlessly
  2. Animated transitions for a smooth UX
  3. Responsive design for various screen sizes
  4. Clean, modern aesthetic with customizable colors

⭐ If you found this solution helpful, please consider giving this project a star on GitHub! Your support helps us continue developing useful tools.

Implementation

Let's start by creating our SlidingLoginSignup component.

Step 1: Setting the theme with Tailwind CSS

We will use Tailwind CSS to style our component. We will also add animations for the sliding effect.

global.css
/* global.css */
@import "tailwindcss";
@theme {
  /* Colors */
  --color-brightColor: #039bab;
  --color-backgroundColor: #03c9d7;
  --color-textColor: #333333;
}
This is global.css file

Step 2: Setting Up the Component

We will use React's useState hook to toggle between Sign In and Sign Up modes.

page.js
"use client";
import React, { useState } from "react";
import Image from "next/image";
import log from "@/public/signin.svg";
import register from "@/public/signup.svg";
import SignInForm from "./components/SignInForm";
import SignUpForm from "./components/SignUpForm";
 
const SlidingLoginSignup = () => {
  const [isSignUpMode, setIsSignUpMode] = useState(false);
 
  const toggleSignUpMode = () => {
    setIsSignUpMode(!isSignUpMode);
  };
 
  // Common button styles
  const buttonClasses =
    `w-full text-white bg-backgroundColor hover:bg-brightColor focus:ring-4 focus:outline-none 
    focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-3 text-center transition-all 
    duration-200 transform hover:scale-[1.02] hover:shadow-md`;
  const buttonForGFT =
    `inline-flex w-full justify-center items-center rounded-lg border border-gray-300 bg-white 
    py-2.5 px-4 text-sm font-medium text-gray-500 hover:bg-gray-50 shadow-sm transition-all 
    duration-200 hover:shadow hover:border-gray-400`;
 
  return (
    <div
      className={`relative w-full bg-white min-h-[100vh] lg:min-h-screen overflow-hidden
           before:content-[''] before:absolute before:w-[1500px] before:h-[1500px] lg:before:h-[2000px] 
           lg:before:w-[2000px] lg:before:top-[-10%]  before:top-[initial] lg:before:right-[48%] 
           before:right-[initial]  max-lg:before:left-[30%] max-sm:bottom-[72%]   max-md:before:left-1/2 
            max-lg:before:bottom-[75%]  before:z-[6] before:rounded-[50%]    max-md:p-6     
            lg:before:-translate-y-1/2  max-lg:before:-translate-x-1/2  before:bg-backgroundColor 
            before:transition-all before:duration-[2s] lg:before:duration-[1.8s]  ${
        isSignUpMode
          ? `lg:before:translate-x-full before:-translate-x-1/2 
          before:translate-y-full lg:before:right-[52%] before:right-[initial]  sm:max-lg:before:bottom-[22%]
           max-sm:before:bottom-[20%]  max-md:before:left-1/2`
          : ""
      }`}
    >
      <div className="absolute w-full h-full top-0 left-0">
        <div
          className={` absolute top-[95%] lg:top-1/2 left-1/2 grid grid-cols-1 z-[5] -translate-x-1/2 
             -translate-y-full lg:-translate-y-1/2 lg:w-1/2 w-full  transition-[1s]  duration-[0.8s] 
             lg:duration-[0.7s] ease-[ease-in-out] "  ${
            isSignUpMode
              ? "lg:left-1/4   max-lg:top-[-10%]   max-lg:-translate-x-2/4   max-lg:translate-y-0"
              : "lg:left-3/4 "
          } `}
        >
          <div
            className={` flex items-center justify-center flex-col   transition-all duration-[0.2s] delay-[0.7s] 
              overflow-hidden col-start-1 col-end-2 row-start-1 row-end-2 px-20 max-lg:mt-60  z-20 max-md:px-6 
              max-md:py-0 ${
              isSignUpMode ? " opacity-0 z-10 " : " "
            }`}
          >
            <SignInForm
              buttonClasses={buttonClasses}
              buttonForGFT={buttonForGFT}
            />
          </div>
 
          <div
            className={`flex items-center justify-center flex-col px-20 transition-all  ease-in-out duration-[0.2s]
               delay-[0.7s] overflow-hidden col-start-1 col-end-2 row-start-1 row-end-2 py-0 z-10 max-md:px-6 
               max-md:py-0 opacity-0 ${
              isSignUpMode ? "opacity-100 z-20 " : "  "
            }`}
          >
            <SignUpForm
              buttonClasses={buttonClasses}
              buttonForGFT={buttonForGFT}
            />
          </div>
        </div>
      </div>
 
      <div className="absolute h-full w-full top-0 left-0 grid grid-cols-1   max-lg:grid-rows-[1fr_2fr_1fr]  
      lg:grid-cols-2">
        <div
          className={`flex flex-row justify-around lg:flex-col items-center  max-lg:col-start-1 max-lg:col-end-2  
            max-lg:px-[8%]   max-lg:py-10 lg:items-end  text-center z-[6]   max-lg:row-start-1 max-lg:row-end-2    
             pl-[12%] pr-[17%] pt-12 pb-8 ${
            isSignUpMode ? "pointer-events-none" : " pointer-events-auto"
          }`}
        >
          <div
            className={`text-white transition-transform duration-[0.9s]  lg:duration-[1.1s] ease-[ease-in-out] 
               delay-[0.8s] lg:delay-[0.4s]   max-lg:pr-[15%]  max-md:px-4  max-md:py-2 ${
              isSignUpMode
                ? "lg:translate-x-[-800px]   max-lg:translate-y-[-300px]"
                : ""
            }`}
          >
            <h3 className="font-semibold leading-none text-[1.2rem] lg:text-[1.5rem] text-gray-700">
              New here ?
            </h3>
            <p className="text-[0.7rem] lg:text-[0.95rem] px-0 py-2 lg:py-[0.7rem]">
            Sign up and discover our platform
            </p>
            <button
              className="bg-transparent w-[110px] h-[35px] text-gray-700 text-[0.7rem] lg:w-[130px] lg:h-[41px] 
              lg:text-[0.8rem]  font-semibold   border-2 border-white rounded-full transition-colors duration-300 
              hover:bg-white hover:text-gray-700"
              id="sign-up-btn"
              onClick={toggleSignUpMode}
            >
              Sign up
            </button>
          </div>
 
          <Image
            src={log}
            className={`  max-md:hidden max-lg:translate-y-[-40px] w-[200px] lg:w-full transition-transform 
              duration-[0.9s] lg:duration-[1.1s] ease-[ease-in-out] delay-[0.6s] lg:delay-[0.4s] ${
              isSignUpMode
                ? "lg:translate-x-[-800px]   max-lg:translate-y-[-300px]"
                : ""
            }`}
            alt="login"
          />
        </div>
        <div
          className={`flex flex-row   max-lg:row-start-3 max-lg:row-end-4 lg:flex-col items-center lg:items-end 
            justify-around text-center z-[6]   max-lg:col-start-1 max-lg:col-end-2  max-lg:px-[8%]   max-lg:py-10 
             pl-[17%] pr-[12%] pt-12 pb-8 ${
            isSignUpMode ? " pointer-events-auto" : "pointer-events-none"
          }`}
        >
          <div
            className={`text-white transition-transform duration-[0.9s] lg:duration-[1.1s] ease-in-out delay-[0.8s]
               lg:delay-[0.4s]   max-lg:pr-[15%] max-md:px-4  max-md:py-2 ${
              isSignUpMode
                ? ""
                : "lg:translate-x-[800px]   max-lg:translate-y-[300px]"
            }`}
          >
            <h3 className="font-semibold leading-none text-[1.2rem] lg:text-[1.5rem] text-gray-700">
              One of us ?
            </h3>
            <p className=" py-2 text-[0.7rem] lg:text-[0.95rem] px-0  lg:py-[0.7rem]">
              Sign in to your account to have hastle free experience
            </p>
            <button
              className=" text-gray-700 bg-transparent w-[110px] h-[35px]  text-[0.7rem] lg:w-[130px] 
              lg:h-[41px] lg:text-[0.8rem]  font-semibold   border-2 border-white rounded-full 
              transition-colors duration-300 hover:bg-white hover:text-gray-700"
              id="sign-in-btn"
              onClick={toggleSignUpMode}
            >
              Sign in
            </button>
          </div>
 
          <Image
            src={register}
            className={`  max-md:hidden w-[200px] lg:w-full transition-transform duration-[0.9s] 
              lg:duration-[1.1s] ease-[ease-in-out] delay-[0.6s] lg:delay-[0.4s] ${
              isSignUpMode
                ? ""
                : "lg:translate-x-[800px]  max-lg:translate-y-[300px]"
            }`}
            alt="register"
          />
        </div>
      </div>
    </div>
  );
};
 
export default SlidingLoginSignup;
This is page.js file

How It Works

Let's break down how this component functions:

  1. State Management: The isSignUpMode state controls which form is displayed and the animation direction.
  2. Animated Container: A large circular pseudo-element slides across the screen during transitions.
  3. Form Switching: Forms fade in and out based on the current mode.
  4. Responsive Design: The layout adjusts across different screen sizes using Tailwind's responsive utilities.

How is that animated circle formed?

🔵 1. The Circle is Created Using a ::before Pseudo-Element

In the outermost <div>, there's no actual <div> tag for the circle — it's made using Tailwind's support for ::before through utility classes.

Check this part:

before:content-[''] 
before:absolute 
before:w-[1500px] 
before:h-[1500px] 
before:rounded-[50%] 
before:bg-backgroundColor

Explore CSS Pseudo Elements in Tailwind CSS

🔍 What this does:

  • before:content-['']: Makes sure the pseudo-element is rendered.
  • before:absolute: Positions it freely within the parent.
  • before:w-[1500px] & before:h-[1500px]: Huge dimensions to ensure the circle covers enough of the screen (especially on desktop).
  • before:rounded-[50%]: Turns that big square into a perfect circle. As width and height are equal, the rounded-[50%] makes it circular.
  • before:bg-backgroundColor: Gives it color.

Result: A large colored circle, sitting behind the form content.

🌀 2. The Circle is Positioned Using translate

Depending on screen size and the isSignUpMode state, the circle is moved using Tailwind’s translation utilities.

Example when isSignUpMode is true:

before:translate-y-full 
lg:before:translate-x-full 

🧠 What this means:

  • The circle moves down or sideways out of the original spot to give a visual sliding effect.
  • This creates a smooth animated transition between login and signup modes — like the UI is morphing.

🎯 3. Animation is Smooth Because of transition

Tailwind is also used to animate the movement:

before:transition-all 
before:duration-[2s]
lg:before:duration-[1.8s]

🎥 This tells the browser to animate all changes (like translate, opacity, etc.) smoothly over 1.8 to 2 seconds.

💡 Summary

So the animated circle works because of:

FeaturePurpose
::beforeCreates a background shape
w + h + rounded-[50%]Makes it a circle
absolute + translateMoves it to specific locations
transition-all + durationAnimates the movement smoothly
Conditional Tailwind classesControl movement based on mode (sign-in vs sign-up)

Explore CSS Positioning in Tailwind CSS

Explore CSS Transform, Translate, and Transition in Tailwind CSS

Positioning

After forming the circle, the position is controlled entirely by utility classes (especially top, left, right, bottom, and translate modifiers) — and these change dynamically based on screen size and sign-up mode.

Let’s walk through it step-by-step.

🧩 Step 1: Initial Positioning (isSignUpMode is false)

Here’s the relevant part of the parent <div> when not in sign-up mode:

before:absolute 
lg:before:top-[-10%] 
lg:before:right-[48%] 
max-lg:before:left-[30%] 
max-md:before:left-1/2 
max-lg:before:bottom-[75%] 
lg:before:-translate-y-1/2 
max-lg:before:-translate-x-1/2

What this does:

ClassMeaning
before:absoluteLet the circle be freely positioned within the relative container
lg:before:top-[-10%]Move the circle slightly above the visible area on large screens
lg:before:right-[48%]Push it a bit from the right on large screens
max-lg:before:left-[30%]On smaller screens, center it horizontally more
max-lg:before:bottom-[75%]Position it towards the bottom vertically on mobile
translate-x, translate-yHelps center the circle around a focal point instead of aligning from the top-left
ClassEffect
-translate-y-1/2Moves up (negative Y direction)
translate-y-1/2Moves down (positive Y direction)
-translate-x-1/2Moves left (negative X direction)
translate-x-1/2Moves right (positive X direction)

So basically: it’s off-center and sitting behind the Sign In form, styled just enough to be visually appealing.

🔁 Step 2: Position Change When isSignUpMode is True

Now, look at this conditional block:

${isSignUpMode ? 
  `lg:before:translate-x-full 
   lg:before:-translate-y-1/2 
   before:-translate-x-1/2 
   before:translate-y-full 
   lg:before:right-[52%] 
   sm:max-lg:before:bottom-[22%]
   max-sm:before:bottom-[20%]
   max-md:before:left-1/2` 
: ""}

🔄 What’s changing here?

ClassEffect
lg:before:translate-x-fullSlides the circle all the way to the right on large screens
before:translate-y-fullMoves the circle vertically down when not in Large Screen
lg:before:right-[52%]Re-positions the circle slightly more left from the right edge
max-sm:before:bottom-[20%]Adjust vertical position on small screens
max-md:before:left-1/2Horizontally centers it on tablets/small screens

🧠 These classes move the circle so that it visually supports the Sign Up form — which also slides in from the right.

Summary: How the Circle is Positioned

StateHow It's Positioned
Initial (Sign In)Slightly off to the left/top using right-[48%] and top-[-10%], with Y-translate
Sign Up modeSlides to the right (translate-x-full), down (translate-y-full), and adjusts right and bottom values
Responsive DesignUses max-lg, max-md, max-sm to reposition the circle on smaller screens so the UX still works

Wheel-Like Movement

The circle "feels" like it's rotating or rolling like a wheel, right? But here's the catch:

It's Actually an Illusion — Not Real Rotation!

Let me explain:

🌀 The Wheel-Like Movement — How It's Actually Implemented

In the code, there's no actual rotate or spinning transform applied to the ::before circle.

lg:before:translate-x-full 
lg:before:-translate-y-1/2

This means:

  • On large screens, the circle is primarily moving horizontally, not diagonally.

  • The -translate-y-1/2 is actually applied in both states (sign-in and sign-up), so there's no vertical change during the transition.

  • Because it's a perfect circle and extremely large (2000px × 2000px on large screens), the horizontal movement creates an illusion of rolling.

🤯 Why It Feels Like Rotation

Here's what makes it feel like it's rotating:

Visual ElementIllusion Trigger
Circle shapeA rolling circle is expected to spin
Large size relative to viewportOnly seeing part of the circle makes the movement seem more complex
Smooth easing + durationThe 1.8s transition mimics momentum like a wheel
Content shifting with itEnhances motion illusion
Positioning adjustmentsThe slight shift from right-[48%] to right-[52%] enhances the motion

Even without rotation or diagonal movement, our brain associates the horizontal motion of a massive circle with a rolling wheel. This is a clever visual trick that creates a sophisticated animation effect with simple CSS transforms.

On smaller screens, the behavior is different, using before:-translate-x-1/2 before:translate-y-full which creates a more vertical movement pattern.

What Happens After Positioning?

So far, we've covered:

  • ✅ How the circle is created using ::before
  • ✅ How the circle is positioned initially for Sign In mode
  • ✅ How it translates/moves for Sign Up mode using conditional classes

🧱 What Happens After the Circle Moves?

Once the circle is animated into its new position, it becomes part of a larger transition that gives the illusion of sliding between forms.

Let’s break down what happens next:

🧩 Form Panel Positioning — How Forms Slide With the Circle

After the circle moves...

<div className="absolute w-full h-full top-0 left-0">
  <div className={...}>
    <div className={isSignUpMode ? "opacity-0 z-10" : "opacity-100 z-20"}>
      <SignInForm />
    </div>
    <div className={isSignUpMode ? "opacity-100 z-20" : "opacity-0 z-10"}>
      <SignUpForm />
    </div>
  </div>
</div>

Here’s what’s happening:

ItemEffect
opacity-0 / opacity-100Fades out one form and fades in the other
z-10 / z-20Controls which form is clickable or visible on top
translate-x, translate-y (from parent container)Controls the sliding direction (left or right)

So as the circle animates, the form container also shifts, syncing the visual experience.

🖼️ Side Panels (Text + Image) Animate Too

The two side panels — “New here?” and “One of us?” — also animate their content based on isSignUpMode.

Examples:

{isSignUpMode 
  ? "lg:translate-x-[-800px]" 
  : "lg:translate-x-[800px]"
}

This means:

  • The login image and text slide out to the left
  • The sign-up image and text slide in from the right

So now:

  • 🔵 The background circle shifts
  • 🧩 The form panel slides and fades
  • 🖼️ The side text panels animate out/in

All transitions happen together using:

  • translate
  • opacity
  • transition-all, duration, delay
  • Conditional rendering based on isSignUpMode

🎯 Final Result

It looks like the entire login/signup page morphs — but technically:

  • The circle background shifts
  • The forms fade and slide
  • The side content swaps via translate

This gives your app a modern, smooth, and interactive transition between login and sign-up — and it’s all done purely with React + Tailwind, no animations libraries needed.

Responsive Design Showcase

The desktop layout features side-by-side panels with smooth horizontal transitions between modes.

Medium Screen View

On medium screens, the layout adjusts to ensure the content remains readable and visually appealing. The forms and buttons resize appropriately, and the sliding animations remain smooth.

Sliding authentication component on medium screen

Mobile View

On small screens, the layout adapts with vertical stacking, ensuring the component remains functional and visually coherent on mobile devices.

Sliding authentication component on mobile screen

Customization Options

You can easily customize this component to match your application's branding:

  1. Colors: Update the theme variables in global.css
  2. Images: Replace the SVG illustrations with your own assets
  3. Form Content: Add your own form fields, validation, and submission logic
  4. Animation Timing: Adjust the duration and ease values in the transition classes