Multi Step Registration Form
A responsive multi-step registration form with account and profile steps, live validation, password strength feedback, review controls and a success state.
Join CodeRipple
Complete the steps below to set up your profile.
Account Created!
Your demo registration has been completed successfully.
<div class="cr-step-form" id="crStepForm">
<div class="cr-step-form__card">
<!-- Header -->
<div class="cr-step-form__header">
<span class="cr-step-form__eyebrow">CREATE YOUR ACCOUNT</span>
<h2>Join CodeRipple</h2>
<p>Complete the steps below to set up your profile.</p>
</div>
<!-- Progress -->
<div class="cr-step-form__progress">
<div class="cr-step cr-step--active" data-step-indicator="1">
<div class="cr-step__circle">
<span>1</span>
</div>
<div class="cr-step__text">
<strong>Account</strong>
<small>Login details</small>
</div>
</div>
<div class="cr-step__line">
<span></span>
</div>
<div class="cr-step" data-step-indicator="2">
<div class="cr-step__circle">
<span>2</span>
</div>
<div class="cr-step__text">
<strong>Profile</strong>
<small>About you</small>
</div>
</div>
<div class="cr-step__line">
<span></span>
</div>
<div class="cr-step" data-step-indicator="3">
<div class="cr-step__circle">
<span>3</span>
</div>
<div class="cr-step__text">
<strong>Review</strong>
<small>Confirm details</small>
</div>
</div>
</div>
<!-- Form -->
<form class="cr-step-form__form" novalidate>
<!-- STEP 1 -->
<section class="cr-form-step cr-form-step--active" data-step="1">
<div class="cr-form-step__heading">
<span class="cr-form-step__number">01</span>
<div>
<h3>Account Details</h3>
<p>Choose the credentials you'll use to sign in.</p>
</div>
</div>
<div class="cr-field">
<label for="crEmail">Email Address</label>
<div class="cr-input-wrap">
<span class="cr-input-icon" aria-hidden="true">
<svg viewBox="0 0 24 24">
<path d="M4 6h16v12H4z"></path>
<path d="m4 7 8 6 8-6"></path>
</svg>
</span>
<input
type="email"
id="crEmail"
name="email"
placeholder="you@example.com"
autocomplete="email"
required
>
</div>
<span class="cr-field__error"></span>
</div>
<div class="cr-field">
<label for="crPassword">Password</label>
<div class="cr-input-wrap">
<span class="cr-input-icon" aria-hidden="true">
<svg viewBox="0 0 24 24">
<rect x="5" y="10" width="14" height="10" rx="2"></rect>
<path d="M8 10V7a4 4 0 0 1 8 0v3"></path>
</svg>
</span>
<input
type="password"
id="crPassword"
name="password"
placeholder="Create a password"
autocomplete="new-password"
minlength="8"
required
>
<button
class="cr-password-toggle"
type="button"
aria-label="Show password"
>
<svg class="cr-eye-icon" viewBox="0 0 24 24">
<path d="M2.5 12s3.5-6 9.5-6 9.5 6 9.5 6-3.5 6-9.5 6-9.5-6-9.5-6z"></path>
<circle cx="12" cy="12" r="2.5"></circle>
</svg>
</button>
</div>
<div class="cr-password-strength">
<span></span>
<span></span>
<span></span>
<span></span>
</div>
<div class="cr-password-meta">
<small class="cr-password-hint">Minimum 8 characters</small>
<small class="cr-password-status">Password strength</small>
</div>
<span class="cr-field__error"></span>
</div>
<div class="cr-field">
<label for="crConfirmPassword">Confirm Password</label>
<div class="cr-input-wrap">
<span class="cr-input-icon" aria-hidden="true">
<svg viewBox="0 0 24 24">
<rect x="5" y="10" width="14" height="10" rx="2"></rect>
<path d="M8 10V7a4 4 0 0 1 8 0v3"></path>
</svg>
</span>
<input
type="password"
id="crConfirmPassword"
name="confirmPassword"
placeholder="Repeat your password"
autocomplete="new-password"
required
>
</div>
<span class="cr-field__error"></span>
</div>
</section>
<!-- STEP 2 -->
<section class="cr-form-step" data-step="2">
<div class="cr-form-step__heading">
<span class="cr-form-step__number">02</span>
<div>
<h3>Your Profile</h3>
<p>Tell us a little more about yourself.</p>
</div>
</div>
<div class="cr-field-row">
<div class="cr-field">
<label for="crFirstName">First Name</label>
<div class="cr-input-wrap">
<span class="cr-input-icon" aria-hidden="true">
<svg viewBox="0 0 24 24">
<circle cx="12" cy="8" r="4"></circle>
<path d="M4 21c0-4 3.6-7 8-7s8 3 8 7"></path>
</svg>
</span>
<input
type="text"
id="crFirstName"
name="firstName"
placeholder="First name"
autocomplete="given-name"
required
>
</div>
<span class="cr-field__error"></span>
</div>
<div class="cr-field">
<label for="crLastName">Last Name</label>
<div class="cr-input-wrap">
<span class="cr-input-icon" aria-hidden="true">
<svg viewBox="0 0 24 24">
<circle cx="12" cy="8" r="4"></circle>
<path d="M4 21c0-4 3.6-7 8-7s8 3 8 7"></path>
</svg>
</span>
<input
type="text"
id="crLastName"
name="lastName"
placeholder="Last name"
autocomplete="family-name"
required
>
</div>
<span class="cr-field__error"></span>
</div>
</div>
<div class="cr-field">
<label for="crUsername">Username</label>
<div class="cr-input-wrap">
<span class="cr-input-icon" aria-hidden="true">@</span>
<input
type="text"
id="crUsername"
name="username"
placeholder="Choose a username"
autocomplete="username"
minlength="3"
required
>
</div>
<span class="cr-field__hint">
Letters, numbers and underscores only.
</span>
<span class="cr-field__error"></span>
</div>
<div class="cr-field">
<label for="crRole">What best describes you?</label>
<div class="cr-select-wrap">
<select id="crRole" name="role" required>
<option value="">Select your role</option>
<option value="developer">Developer</option>
<option value="designer">Designer</option>
<option value="student">Student</option>
<option value="freelancer">Freelancer</option>
<option value="creator">Content Creator</option>
<option value="other">Other</option>
</select>
</div>
<span class="cr-field__error"></span>
</div>
<div class="cr-field">
<label for="crBio">
Short Bio
<span class="cr-label-optional">Optional</span>
</label>
<textarea
id="crBio"
name="bio"
maxlength="160"
placeholder="Tell us something about yourself..."
></textarea>
<div class="cr-field__meta">
<span>You can change this later.</span>
<span><strong id="crBioCount">0</strong>/160</span>
</div>
</div>
</section>
<!-- STEP 3 -->
<section class="cr-form-step" data-step="3">
<div class="cr-form-step__heading">
<span class="cr-form-step__number">03</span>
<div>
<h3>Review & Submit</h3>
<p>Check your information before creating your account.</p>
</div>
</div>
<div class="cr-review">
<div class="cr-review__section">
<div class="cr-review__section-head">
<div>
<span>01</span>
<strong>Account</strong>
</div>
<button type="button" class="cr-review-edit" data-edit-step="1">
Edit
</button>
</div>
<div class="cr-review__grid">
<div class="cr-review__item">
<small>Email Address</small>
<strong data-review="email">Not provided</strong>
</div>
<div class="cr-review__item">
<small>Password</small>
<strong data-review="password">••••••••</strong>
</div>
</div>
</div>
<div class="cr-review__section">
<div class="cr-review__section-head">
<div>
<span>02</span>
<strong>Profile</strong>
</div>
<button type="button" class="cr-review-edit" data-edit-step="2">
Edit
</button>
</div>
<div class="cr-review__grid">
<div class="cr-review__item">
<small>Full Name</small>
<strong data-review="name">Not provided</strong>
</div>
<div class="cr-review__item">
<small>Username</small>
<strong data-review="username">Not provided</strong>
</div>
<div class="cr-review__item">
<small>Role</small>
<strong data-review="role">Not provided</strong>
</div>
<div class="cr-review__item">
<small>Bio</small>
<strong data-review="bio">Not provided</strong>
</div>
</div>
</div>
</div>
<label class="cr-checkbox">
<input type="checkbox" id="crTerms" name="terms" required>
<span class="cr-checkbox__box">
<svg viewBox="0 0 24 24">
<path d="m5 12 4 4L19 7"></path>
</svg>
</span>
<span>
I agree to the
<a href="#" onclick="return false;">Terms of Service</a>
and
<a href="#" onclick="return false;">Privacy Policy</a>.
</span>
</label>
<span class="cr-field__error cr-terms-error"></span>
</section>
<!-- Navigation -->
<div class="cr-step-form__actions">
<button
type="button"
class="cr-btn cr-btn--back"
id="crBackBtn"
disabled
>
<span aria-hidden="true">←</span>
Back
</button>
<div class="cr-step-form__counter">
Step <strong id="crCurrentStep">1</strong> of 3
</div>
<button
type="button"
class="cr-btn cr-btn--next"
id="crNextBtn"
>
Next Step
<span aria-hidden="true">→</span>
</button>
<button
type="submit"
class="cr-btn cr-btn--submit"
id="crSubmitBtn"
hidden
>
Create Account
<span aria-hidden="true">✓</span>
</button>
</div>
</form>
<!-- Success State -->
<div class="cr-success" hidden>
<div class="cr-success__icon">
<svg viewBox="0 0 24 24">
<path d="m5 12 4 4L19 7"></path>
</svg>
</div>
<span class="cr-success__eyebrow">ALL DONE</span>
<h3>Account Created!</h3>
<p>
Your demo registration has been completed successfully.
</p>
<button type="button" class="cr-btn cr-btn--restart">
Start Again
</button>
</div>
</div>
</div>
/* =====================================================
CODERIPPLE MULTI-STEP REGISTRATION FORM
CLEAN PLAYGROUND CSS
===================================================== */
.cr-step-form,
.cr-step-form * {
box-sizing: border-box;
}
.cr-step-form {
--cr-bg: #070a14;
--cr-panel: #101426;
--cr-field: #080c19;
--cr-border: rgba(255, 255, 255, 0.09);
--cr-border-soft: rgba(255, 255, 255, 0.06);
--cr-text: #f5f7ff;
--cr-muted: #858da9;
--cr-purple: #8658ff;
--cr-cyan: #28d7ff;
--cr-green: #3de3a0;
--cr-danger: #ff6680;
width: 100%;
height: auto;
padding: 24px;
position: relative;
font-family:
Inter,
system-ui,
-apple-system,
BlinkMacSystemFont,
"Segoe UI",
sans-serif;
color: var(--cr-text);
background:
radial-gradient(
circle at 10% 10%,
rgba(134, 88, 255, 0.16),
transparent 30%
),
radial-gradient(
circle at 90% 90%,
rgba(40, 215, 255, 0.1),
transparent 30%
),
var(--cr-bg);
}
/* =====================================================
MAIN CARD
===================================================== */
.cr-step-form__card {
width: 100%;
max-width: 1180px;
height: auto;
margin: 0 auto;
padding: 28px 36px 26px;
position: relative;
border: 1px solid var(--cr-border);
border-radius: 24px;
background:
linear-gradient(
145deg,
rgba(18, 22, 43, 0.97),
rgba(9, 12, 25, 0.98)
);
box-shadow:
0 24px 65px rgba(0, 0, 0, 0.32),
inset 0 1px 0 rgba(255, 255, 255, 0.04);
}
/* top glow line */
.cr-step-form__card::before {
content: "";
position: absolute;
top: -1px;
left: 15%;
width: 70%;
height: 1px;
background:
linear-gradient(
90deg,
transparent,
var(--cr-purple),
var(--cr-cyan),
transparent
);
}
/* =====================================================
HEADER
===================================================== */
.cr-step-form__header {
margin-bottom: 22px;
text-align: center;
}
.cr-step-form__eyebrow {
display: inline-block;
margin-bottom: 7px;
color: var(--cr-cyan);
font-size: 10px;
font-weight: 800;
letter-spacing: 0.18em;
}
.cr-step-form__header h2 {
margin: 0;
font-size: 29px;
line-height: 1.15;
font-weight: 800;
letter-spacing: -0.04em;
background:
linear-gradient(
90deg,
#ffffff,
#c9c3ff 55%,
#72e8ff
);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.cr-step-form__header p {
margin: 6px 0 0;
color: var(--cr-muted);
font-size: 11px;
line-height: 1.55;
}
/* =====================================================
PROGRESS BAR
===================================================== */
.cr-step-form__progress {
width: 100%;
display: flex;
align-items: center;
padding: 13px 17px;
margin-bottom: 22px;
border: 1px solid var(--cr-border-soft);
border-radius: 15px;
background: rgba(4, 7, 17, 0.38);
}
.cr-step {
display: flex;
align-items: center;
gap: 9px;
flex-shrink: 0;
opacity: 0.45;
transition:
opacity 0.3s ease,
transform 0.3s ease;
}
.cr-step--active,
.cr-step--complete {
opacity: 1;
}
.cr-step--active {
transform: translateY(-1px);
}
.cr-step__circle {
width: 34px;
height: 34px;
display: grid;
place-items: center;
flex: 0 0 34px;
border: 1px solid rgba(255, 255, 255, 0.11);
border-radius: 50%;
color: #8991ad;
background: rgba(255, 255, 255, 0.035);
font-size: 10px;
font-weight: 800;
transition: 0.3s ease;
}
.cr-step--active .cr-step__circle {
color: #ffffff;
border-color: rgba(40, 215, 255, 0.5);
background:
linear-gradient(
135deg,
var(--cr-purple),
#665cff 55%,
var(--cr-cyan)
);
box-shadow:
0 0 0 4px rgba(134, 88, 255, 0.08),
0 0 20px rgba(40, 215, 255, 0.16);
}
.cr-step--complete .cr-step__circle {
color: #06130e;
border-color: transparent;
background: var(--cr-green);
}
.cr-step__text {
display: flex;
flex-direction: column;
gap: 1px;
}
.cr-step__text strong {
color: #f5f6ff;
font-size: 10px;
font-weight: 700;
}
.cr-step__text small {
color: #707994;
font-size: 8px;
white-space: nowrap;
}
.cr-step__line {
height: 1px;
flex: 1;
min-width: 40px;
margin: 0 18px;
position: relative;
overflow: hidden;
background: rgba(255, 255, 255, 0.08);
}
.cr-step__line span {
position: absolute;
inset: 0;
transform: scaleX(0);
transform-origin: left;
background:
linear-gradient(
90deg,
var(--cr-purple),
var(--cr-cyan)
);
transition: transform 0.4s ease;
}
.cr-step__line--complete span {
transform: scaleX(1);
}
/* =====================================================
FORM STEPS
===================================================== */
.cr-form-step {
display: none;
animation: crStepEnter 0.3s ease;
}
.cr-form-step--active {
display: block;
}
@keyframes crStepEnter {
from {
opacity: 0;
transform: translateY(7px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* =====================================================
STEP 1 WIDE LAYOUT
===================================================== */
.cr-form-step[data-step="1"].cr-form-step--active {
display: grid;
grid-template-columns:
minmax(0, 1fr)
minmax(0, 1fr);
column-gap: 22px;
}
.cr-form-step[data-step="1"] .cr-form-step__heading {
grid-column: 1 / -1;
}
.cr-form-step[data-step="1"] .cr-field:first-of-type {
grid-column: 1 / -1;
}
.cr-form-step[data-step="1"] .cr-field:nth-of-type(2) {
grid-column: 1;
}
.cr-form-step[data-step="1"] .cr-field:nth-of-type(3) {
grid-column: 2;
}
/* =====================================================
STEP 2 WIDE LAYOUT
===================================================== */
.cr-form-step[data-step="2"].cr-form-step--active {
display: grid;
grid-template-columns:
minmax(0, 1fr)
minmax(0, 1fr);
column-gap: 22px;
}
.cr-form-step[data-step="2"] .cr-form-step__heading {
grid-column: 1 / -1;
}
.cr-form-step[data-step="2"] .cr-field-row {
grid-column: 1 / -1;
display: grid;
grid-template-columns:
minmax(0, 1fr)
minmax(0, 1fr);
gap: 22px;
}
.cr-form-step[data-step="2"] > .cr-field:nth-of-type(1) {
grid-column: 1;
}
.cr-form-step[data-step="2"] > .cr-field:nth-of-type(2) {
grid-column: 2;
}
.cr-form-step[data-step="2"] > .cr-field:nth-of-type(3) {
grid-column: 1 / -1;
}
/* =====================================================
STEP HEADING
===================================================== */
.cr-form-step__heading {
display: flex;
align-items: center;
gap: 12px;
padding-bottom: 15px;
margin-bottom: 17px;
border-bottom: 1px solid var(--cr-border-soft);
}
.cr-form-step__number {
width: 39px;
height: 39px;
display: grid;
place-items: center;
flex: 0 0 39px;
border: 1px solid rgba(134, 88, 255, 0.28);
border-radius: 11px;
color: var(--cr-cyan);
background:
linear-gradient(
145deg,
rgba(134, 88, 255, 0.14),
rgba(40, 215, 255, 0.05)
);
font-size: 9px;
font-weight: 900;
letter-spacing: 0.07em;
}
.cr-form-step__heading h3 {
margin: 0 0 3px;
color: #f7f8ff;
font-size: 16px;
line-height: 1.2;
}
.cr-form-step__heading p {
margin: 0;
color: var(--cr-muted);
font-size: 9px;
line-height: 1.5;
}
/* =====================================================
FIELDS
===================================================== */
.cr-field {
min-width: 0;
margin-bottom: 12px;
}
.cr-field label {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 5px;
color: #dce0f1;
font-size: 10px;
font-weight: 650;
}
.cr-label-optional {
color: #69728d;
font-size: 8px;
font-weight: 500;
}
/* =====================================================
INPUT WRAPPER
===================================================== */
.cr-input-wrap {
width: 100%;
height: 44px;
display: flex;
align-items: center;
position: relative;
border: 1px solid rgba(255, 255, 255, 0.09);
border-radius: 11px;
background: rgba(4, 7, 17, 0.6);
transition:
border-color 0.2s ease,
background 0.2s ease,
box-shadow 0.2s ease;
}
.cr-input-wrap:hover {
border-color: rgba(255, 255, 255, 0.14);
}
.cr-input-wrap:focus-within {
border-color: rgba(40, 215, 255, 0.48);
background: rgba(5, 8, 20, 0.82);
box-shadow:
0 0 0 3px rgba(40, 215, 255, 0.04);
}
.cr-input-icon {
width: 41px;
display: grid;
place-items: center;
flex: 0 0 41px;
color: #707996;
font-size: 12px;
font-weight: 700;
}
.cr-input-icon svg {
width: 15px;
height: 15px;
fill: none;
stroke: currentColor;
stroke-width: 1.7;
stroke-linecap: round;
stroke-linejoin: round;
}
.cr-input-wrap input {
width: 100%;
height: 100%;
min-width: 0;
padding: 0 42px 0 0;
border: 0;
outline: 0;
color: #f6f7ff;
background: transparent;
font: inherit;
font-size: 10px;
}
.cr-input-wrap input::placeholder,
.cr-field textarea::placeholder {
color: #606984;
}
/* =====================================================
PASSWORD BUTTON
===================================================== */
.cr-password-toggle {
width: 36px;
height: 36px;
display: grid;
place-items: center;
position: absolute;
top: 50%;
right: 4px;
transform: translateY(-50%);
padding: 0;
border: 0;
border-radius: 8px;
color: #727c99;
background: transparent;
cursor: pointer;
}
.cr-password-toggle:hover {
color: var(--cr-cyan);
background: rgba(255, 255, 255, 0.04);
}
.cr-eye-icon {
width: 16px;
height: 16px;
fill: none;
stroke: currentColor;
stroke-width: 1.6;
stroke-linecap: round;
stroke-linejoin: round;
}
/* =====================================================
PASSWORD STRENGTH
===================================================== */
.cr-password-strength {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 4px;
margin-top: 6px;
}
.cr-password-strength span {
height: 3px;
border-radius: 20px;
background: rgba(255, 255, 255, 0.08);
}
.cr-password-strength[data-strength="1"] span:nth-child(1) {
background: var(--cr-danger);
}
.cr-password-strength[data-strength="2"] span:nth-child(-n + 2) {
background: #ffb74d;
}
.cr-password-strength[data-strength="3"] span:nth-child(-n + 3) {
background: var(--cr-cyan);
}
.cr-password-strength[data-strength="4"] span {
background: var(--cr-green);
}
.cr-password-meta {
display: flex;
justify-content: space-between;
gap: 10px;
margin-top: 4px;
}
.cr-password-meta small {
color: #68718c;
font-size: 8px;
}
/* =====================================================
SELECT
===================================================== */
.cr-select-wrap {
position: relative;
}
.cr-select-wrap::after {
content: "";
width: 6px;
height: 6px;
position: absolute;
top: 17px;
right: 16px;
border-right: 2px solid #78819d;
border-bottom: 2px solid #78819d;
transform: rotate(45deg);
pointer-events: none;
}
.cr-select-wrap select {
width: 100%;
height: 44px;
padding: 0 40px 0 13px;
appearance: none;
-webkit-appearance: none;
border: 1px solid rgba(255, 255, 255, 0.09);
border-radius: 11px;
outline: none;
color: #e7e9f6;
background: #090d1b;
font: inherit;
font-size: 10px;
cursor: pointer;
}
.cr-select-wrap select:focus {
border-color: rgba(40, 215, 255, 0.48);
box-shadow:
0 0 0 3px rgba(40, 215, 255, 0.04);
}
/* =====================================================
TEXTAREA
===================================================== */
.cr-field textarea {
width: 100%;
min-height: 72px;
padding: 11px 13px;
resize: vertical;
border: 1px solid rgba(255, 255, 255, 0.09);
border-radius: 11px;
outline: none;
color: #f5f6ff;
background: rgba(4, 7, 17, 0.6);
font: inherit;
font-size: 10px;
line-height: 1.5;
}
.cr-field textarea:focus {
border-color: rgba(40, 215, 255, 0.48);
box-shadow:
0 0 0 3px rgba(40, 215, 255, 0.04);
}
/* =====================================================
FIELD HINTS
===================================================== */
.cr-field__hint {
display: block;
margin-top: 4px;
color: #68718c;
font-size: 8px;
}
.cr-field__meta {
display: flex;
justify-content: space-between;
margin-top: 4px;
color: #68718c;
font-size: 8px;
}
.cr-field__error {
display: block;
min-height: 10px;
margin-top: 3px;
color: var(--cr-danger);
font-size: 8px;
}
.cr-field--error .cr-input-wrap,
.cr-field--error textarea,
.cr-field--error .cr-select-wrap select {
border-color: rgba(255, 102, 128, 0.6);
}
.cr-field--valid .cr-input-wrap {
border-color: rgba(61, 227, 160, 0.42);
}
/* =====================================================
REVIEW
===================================================== */
.cr-review {
display: grid;
grid-template-columns:
minmax(0, 1fr)
minmax(0, 1fr);
gap: 15px;
}
.cr-review__section {
overflow: hidden;
border: 1px solid var(--cr-border);
border-radius: 14px;
background: rgba(4, 7, 17, 0.42);
}
.cr-review__section-head {
min-height: 47px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 9px 13px;
border-bottom: 1px solid var(--cr-border-soft);
background: rgba(255, 255, 255, 0.02);
}
.cr-review__section-head > div {
display: flex;
align-items: center;
gap: 8px;
}
.cr-review__section-head span {
width: 25px;
height: 25px;
display: grid;
place-items: center;
border-radius: 7px;
color: var(--cr-cyan);
background: rgba(40, 215, 255, 0.07);
font-size: 8px;
font-weight: 800;
}
.cr-review__section-head strong {
color: #f2f4ff;
font-size: 10px;
}
.cr-review-edit {
padding: 5px 9px;
border: 1px solid rgba(134, 88, 255, 0.25);
border-radius: 7px;
color: #b7a8ff;
background: rgba(134, 88, 255, 0.08);
font: inherit;
font-size: 8px;
font-weight: 700;
cursor: pointer;
}
.cr-review-edit:hover {
color: #ffffff;
border-color: rgba(40, 215, 255, 0.35);
}
.cr-review__grid {
display: grid;
grid-template-columns:
minmax(0, 1fr)
minmax(0, 1fr);
}
.cr-review__item {
min-width: 0;
padding: 12px 13px;
border-right: 1px solid var(--cr-border-soft);
border-bottom: 1px solid var(--cr-border-soft);
}
.cr-review__item:nth-child(even) {
border-right: 0;
}
.cr-review__item small {
display: block;
margin-bottom: 4px;
color: #69728e;
font-size: 7px;
text-transform: uppercase;
letter-spacing: 0.06em;
}
.cr-review__item strong {
display: block;
overflow: hidden;
color: #dfe2f2;
font-size: 9px;
font-weight: 600;
white-space: nowrap;
text-overflow: ellipsis;
}
/* =====================================================
CHECKBOX
===================================================== */
.cr-checkbox {
display: flex !important;
align-items: flex-start !important;
justify-content: flex-start !important;
gap: 9px;
margin-top: 15px !important;
color: #8992ad !important;
font-size: 9px !important;
font-weight: 400 !important;
line-height: 1.5;
cursor: pointer;
}
.cr-checkbox input {
position: absolute;
opacity: 0;
pointer-events: none;
}
.cr-checkbox__box {
width: 17px;
height: 17px;
display: grid;
place-items: center;
flex: 0 0 17px;
border: 1px solid rgba(255, 255, 255, 0.15);
border-radius: 5px;
background: rgba(255, 255, 255, 0.03);
}
.cr-checkbox__box svg {
width: 11px;
height: 11px;
fill: none;
stroke: #ffffff;
stroke-width: 2.5;
stroke-linecap: round;
stroke-linejoin: round;
opacity: 0;
transform: scale(0.5);
transition: 0.2s ease;
}
.cr-checkbox input:checked + .cr-checkbox__box {
border-color: transparent;
background:
linear-gradient(
135deg,
var(--cr-purple),
var(--cr-cyan)
);
}
.cr-checkbox input:checked + .cr-checkbox__box svg {
opacity: 1;
transform: scale(1);
}
.cr-checkbox a {
color: #aa9cff;
text-decoration: none;
}
.cr-checkbox a:hover {
color: var(--cr-cyan);
}
/* =====================================================
ACTIONS
===================================================== */
.cr-step-form__actions {
display: grid;
grid-template-columns:
minmax(0, 1fr)
auto
minmax(0, 1fr);
align-items: center;
gap: 13px;
padding-top: 15px;
margin-top: 2px;
border-top: 1px solid var(--cr-border-soft);
}
.cr-btn {
min-height: 40px;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 7px;
padding: 0 17px;
border-radius: 10px;
font: inherit;
font-size: 9px;
font-weight: 750;
cursor: pointer;
transition:
transform 0.2s ease,
box-shadow 0.2s ease,
border-color 0.2s ease;
}
.cr-btn--back {
justify-self: start;
border: 1px solid rgba(255, 255, 255, 0.09);
color: #bec4d8;
background: rgba(255, 255, 255, 0.03);
}
.cr-btn--back:hover:not(:disabled) {
border-color: rgba(255, 255, 255, 0.18);
}
.cr-btn:disabled {
opacity: 0.32;
cursor: not-allowed;
}
.cr-btn--next,
.cr-btn--submit {
min-width: 128px;
justify-self: end;
border: 0;
color: #ffffff;
background:
linear-gradient(
100deg,
#8658ff,
#665cff 55%,
#26cfee
);
box-shadow:
0 9px 22px rgba(108, 82, 255, 0.2),
inset 0 1px 0 rgba(255, 255, 255, 0.2);
}
.cr-btn--next:hover,
.cr-btn--submit:hover {
transform: translateY(-1px);
box-shadow:
0 12px 28px rgba(108, 82, 255, 0.28);
}
.cr-step-form__counter {
color: #68718d;
font-size: 8px;
text-align: center;
}
.cr-step-form__counter strong {
color: #c9cddd;
}
/* =====================================================
SUCCESS
===================================================== */
.cr-success {
padding: 35px 20px 22px;
text-align: center;
animation: crStepEnter 0.35s ease;
}
.cr-success__icon {
width: 62px;
height: 62px;
display: grid;
place-items: center;
margin: 0 auto 17px;
border-radius: 50%;
background:
linear-gradient(
135deg,
var(--cr-purple),
var(--cr-cyan)
);
box-shadow:
0 0 0 7px rgba(134, 88, 255, 0.07),
0 0 32px rgba(40, 215, 255, 0.15);
}
.cr-success__icon svg {
width: 27px;
height: 27px;
fill: none;
stroke: #ffffff;
stroke-width: 2.2;
stroke-linecap: round;
stroke-linejoin: round;
}
.cr-success__eyebrow {
color: var(--cr-green);
font-size: 8px;
font-weight: 800;
letter-spacing: 0.18em;
}
.cr-success h3 {
margin: 7px 0;
color: #ffffff;
font-size: 23px;
}
.cr-success p {
max-width: 380px;
margin: 0 auto 20px;
color: var(--cr-muted);
font-size: 10px;
line-height: 1.6;
}
.cr-btn--restart {
min-width: 125px;
border: 1px solid rgba(40, 215, 255, 0.25);
color: #ffffff;
background: rgba(40, 215, 255, 0.07);
}
/* =====================================================
HIDDEN ELEMENTS
===================================================== */
.cr-step-form [hidden] {
display: none !important;
}
/* =====================================================
TABLET
===================================================== */
@media (max-width: 850px) {
.cr-step-form {
padding: 18px 12px;
}
.cr-step-form__card {
padding: 24px 20px;
}
.cr-step__text small {
display: none;
}
.cr-step__line {
margin: 0 11px;
}
.cr-review {
grid-template-columns: 1fr;
}
}
/* =====================================================
MOBILE
===================================================== */
@media (max-width: 650px) {
.cr-step-form {
padding: 12px 8px;
}
.cr-step-form__card {
padding: 21px 14px;
border-radius: 18px;
}
.cr-step-form__header {
margin-bottom: 18px;
}
.cr-step-form__header h2 {
font-size: 25px;
}
.cr-step-form__progress {
padding: 11px;
margin-bottom: 19px;
}
.cr-step__text {
display: none;
}
.cr-step__circle {
width: 32px;
height: 32px;
flex-basis: 32px;
}
.cr-step__line {
min-width: 18px;
margin: 0 7px;
}
.cr-form-step[data-step="1"].cr-form-step--active,
.cr-form-step[data-step="2"].cr-form-step--active {
display: block;
}
.cr-form-step[data-step="2"] .cr-field-row {
display: block;
}
.cr-review {
grid-template-columns: 1fr;
}
.cr-review__grid {
grid-template-columns: 1fr;
}
.cr-review__item {
border-right: 0;
}
.cr-step-form__actions {
grid-template-columns: 1fr 1fr;
}
.cr-step-form__counter {
grid-column: 1 / -1;
grid-row: 1;
}
.cr-btn--back {
grid-column: 1;
grid-row: 2;
width: 100%;
}
.cr-btn--next,
.cr-btn--submit {
grid-column: 2;
grid-row: 2;
width: 100%;
min-width: 0;
}
}
/* =====================================================
SMALL MOBILE
===================================================== */
@media (max-width: 400px) {
.cr-step-form__card {
padding: 19px 11px;
}
.cr-form-step__heading {
align-items: flex-start;
}
.cr-form-step__number {
width: 37px;
height: 37px;
flex-basis: 37px;
}
.cr-input-wrap,
.cr-select-wrap select {
height: 43px;
}
.cr-password-meta {
flex-direction: column;
gap: 2px;
}
}
(() => {
const component = document.querySelector("#crStepForm");
if (!component) return;
/* ==================================================
ELEMENTS
================================================== */
const form = component.querySelector(".cr-step-form__form");
const formSteps = [
...component.querySelectorAll(".cr-form-step")
];
const indicators = [
...component.querySelectorAll("[data-step-indicator]")
];
const progressLines = [
...component.querySelectorAll(".cr-step__line")
];
const backBtn = component.querySelector("#crBackBtn");
const nextBtn = component.querySelector("#crNextBtn");
const submitBtn = component.querySelector("#crSubmitBtn");
const currentStepText =
component.querySelector("#crCurrentStep");
const header =
component.querySelector(".cr-step-form__header");
const progress =
component.querySelector(".cr-step-form__progress");
const success =
component.querySelector(".cr-success");
const restartBtn =
component.querySelector(".cr-btn--restart");
/* ==================================================
INPUTS
================================================== */
const email =
component.querySelector("#crEmail");
const password =
component.querySelector("#crPassword");
const confirmPassword =
component.querySelector("#crConfirmPassword");
const firstName =
component.querySelector("#crFirstName");
const lastName =
component.querySelector("#crLastName");
const username =
component.querySelector("#crUsername");
const role =
component.querySelector("#crRole");
const bio =
component.querySelector("#crBio");
const bioCount =
component.querySelector("#crBioCount");
const terms =
component.querySelector("#crTerms");
const termsError =
component.querySelector(".cr-terms-error");
/* ==================================================
PASSWORD ELEMENTS
================================================== */
const passwordToggle =
component.querySelector(".cr-password-toggle");
const passwordStrength =
component.querySelector(".cr-password-strength");
const passwordStatus =
component.querySelector(".cr-password-status");
/* ==================================================
REVIEW EDIT BUTTONS
================================================== */
const editButtons = [
...component.querySelectorAll("[data-edit-step]")
];
let currentStep = 1;
/* ==================================================
FIELD HELPERS
================================================== */
const getField = (input) => {
if (!input) return null;
return input.closest(".cr-field");
};
const getError = (input) => {
const field = getField(input);
if (!field) return null;
return field.querySelector(".cr-field__error");
};
const showError = (input, message) => {
const field = getField(input);
const error = getError(input);
if (!field) return;
field.classList.add("cr-field--error");
field.classList.remove("cr-field--valid");
if (error) {
error.textContent = message;
}
};
const showValid = (input) => {
const field = getField(input);
const error = getError(input);
if (!field) return;
field.classList.remove("cr-field--error");
field.classList.add("cr-field--valid");
if (error) {
error.textContent = "";
}
};
const clearFieldState = (input) => {
const field = getField(input);
const error = getError(input);
if (!field) return;
field.classList.remove(
"cr-field--error",
"cr-field--valid"
);
if (error) {
error.textContent = "";
}
};
/* ==================================================
EMAIL VALIDATION
================================================== */
const validateEmail = () => {
const value = email.value.trim();
if (!value) {
showError(
email,
"Email address is required."
);
return false;
}
const emailPattern =
/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;
if (!emailPattern.test(value)) {
showError(
email,
"Enter a valid email address."
);
return false;
}
showValid(email);
return true;
};
/* ==================================================
PASSWORD STRENGTH
================================================== */
const getPasswordStrength = (value) => {
if (!value) return 0;
let score = 0;
if (value.length >= 8) {
score++;
}
if (/[A-Z]/.test(value)) {
score++;
}
if (/[0-9]/.test(value)) {
score++;
}
if (/[^A-Za-z0-9]/.test(value)) {
score++;
}
return score;
};
const updatePasswordStrength = () => {
const value = password.value;
if (!value) {
passwordStrength.removeAttribute(
"data-strength"
);
passwordStatus.textContent =
"Password strength";
return;
}
const strength =
getPasswordStrength(value);
passwordStrength.setAttribute(
"data-strength",
String(strength)
);
const labels = {
0: "Very weak",
1: "Weak",
2: "Fair",
3: "Good",
4: "Strong"
};
passwordStatus.textContent =
labels[strength];
};
const validatePassword = () => {
const value = password.value;
if (!value) {
showError(
password,
"Password is required."
);
return false;
}
if (value.length < 8) {
showError(
password,
"Use at least 8 characters."
);
return false;
}
showValid(password);
return true;
};
const validateConfirmPassword = () => {
const value = confirmPassword.value;
if (!value) {
showError(
confirmPassword,
"Please confirm your password."
);
return false;
}
if (value !== password.value) {
showError(
confirmPassword,
"Passwords do not match."
);
return false;
}
showValid(confirmPassword);
return true;
};
/* ==================================================
PROFILE VALIDATION
================================================== */
const validateName = (input, label) => {
const value = input.value.trim();
if (!value) {
showError(
input,
`${label} is required.`
);
return false;
}
if (value.length < 2) {
showError(
input,
`${label} must contain at least 2 characters.`
);
return false;
}
showValid(input);
return true;
};
const validateUsername = () => {
const value = username.value.trim();
if (!value) {
showError(
username,
"Username is required."
);
return false;
}
if (value.length < 3) {
showError(
username,
"Use at least 3 characters."
);
return false;
}
const usernamePattern =
/^[A-Za-z0-9_]+$/;
if (!usernamePattern.test(value)) {
showError(
username,
"Use letters, numbers and underscores only."
);
return false;
}
showValid(username);
return true;
};
const validateRole = () => {
if (!role.value) {
showError(
role,
"Please select your role."
);
return false;
}
showValid(role);
return true;
};
/* ==================================================
STEP VALIDATION
================================================== */
const validateStepOne = () => {
const emailValid =
validateEmail();
const passwordValid =
validatePassword();
const confirmValid =
validateConfirmPassword();
return (
emailValid &&
passwordValid &&
confirmValid
);
};
const validateStepTwo = () => {
const firstValid =
validateName(
firstName,
"First name"
);
const lastValid =
validateName(
lastName,
"Last name"
);
const usernameValid =
validateUsername();
const roleValid =
validateRole();
return (
firstValid &&
lastValid &&
usernameValid &&
roleValid
);
};
/* ==================================================
REVIEW
================================================== */
const setReviewValue = (name, value) => {
const target =
component.querySelector(
`[data-review="${name}"]`
);
if (!target) return;
const cleanValue =
String(value || "").trim();
target.textContent =
cleanValue || "Not provided";
};
const updateReview = () => {
setReviewValue(
"email",
email.value
);
const passwordDots =
password.value
? "•".repeat(
Math.min(
password.value.length,
12
)
)
: "••••••••";
setReviewValue(
"password",
passwordDots
);
const fullName = [
firstName.value.trim(),
lastName.value.trim()
]
.filter(Boolean)
.join(" ");
setReviewValue(
"name",
fullName
);
const usernameValue =
username.value.trim();
setReviewValue(
"username",
usernameValue
? `@${usernameValue}`
: ""
);
const selectedOption =
role.options[
role.selectedIndex
];
setReviewValue(
"role",
role.value && selectedOption
? selectedOption.textContent
: ""
);
setReviewValue(
"bio",
bio.value
);
};
/* ==================================================
PROGRESS
================================================== */
const updateProgress = () => {
indicators.forEach(
(indicator, index) => {
const stepNumber =
index + 1;
indicator.classList.remove(
"cr-step--active",
"cr-step--complete"
);
const number =
indicator.querySelector(
".cr-step__circle span"
);
if (stepNumber < currentStep) {
indicator.classList.add(
"cr-step--complete"
);
if (number) {
number.textContent = "✓";
}
return;
}
if (stepNumber === currentStep) {
indicator.classList.add(
"cr-step--active"
);
}
if (number) {
number.textContent =
String(stepNumber);
}
}
);
progressLines.forEach(
(line, index) => {
line.classList.toggle(
"cr-step__line--complete",
index < currentStep - 1
);
}
);
};
/* ==================================================
SHOW STEP
================================================== */
const showStep = (stepNumber) => {
currentStep = Math.max(
1,
Math.min(stepNumber, 3)
);
formSteps.forEach((step) => {
const number =
Number(step.dataset.step);
step.classList.toggle(
"cr-form-step--active",
number === currentStep
);
});
backBtn.disabled =
currentStep === 1;
if (currentStep === 3) {
updateReview();
nextBtn.hidden = true;
submitBtn.hidden = false;
} else {
nextBtn.hidden = false;
submitBtn.hidden = true;
}
currentStepText.textContent =
String(currentStep);
updateProgress();
};
/* ==================================================
NEXT
================================================== */
nextBtn.addEventListener(
"click",
(event) => {
event.preventDefault();
if (currentStep === 1) {
if (!validateStepOne()) {
return;
}
showStep(2);
return;
}
if (currentStep === 2) {
if (!validateStepTwo()) {
return;
}
updateReview();
showStep(3);
}
}
);
/* ==================================================
BACK
================================================== */
backBtn.addEventListener(
"click",
(event) => {
event.preventDefault();
if (currentStep > 1) {
showStep(
currentStep - 1
);
}
}
);
/* ==================================================
EDIT REVIEW
================================================== */
editButtons.forEach((button) => {
button.addEventListener(
"click",
(event) => {
event.preventDefault();
const stepNumber =
Number(
button.dataset.editStep
);
if (!stepNumber) return;
showStep(stepNumber);
}
);
});
/* ==================================================
PASSWORD SHOW / HIDE
================================================== */
if (passwordToggle) {
passwordToggle.addEventListener(
"click",
(event) => {
event.preventDefault();
const hidden =
password.type === "password";
password.type =
hidden
? "text"
: "password";
passwordToggle.setAttribute(
"aria-label",
hidden
? "Hide password"
: "Show password"
);
}
);
}
/* ==================================================
LIVE VALIDATION
================================================== */
email.addEventListener(
"blur",
validateEmail
);
email.addEventListener(
"input",
() => {
const field =
getField(email);
if (
field &&
field.classList.contains(
"cr-field--error"
)
) {
validateEmail();
}
}
);
password.addEventListener(
"input",
() => {
updatePasswordStrength();
const field =
getField(password);
if (
field &&
field.classList.contains(
"cr-field--error"
)
) {
validatePassword();
}
if (
confirmPassword.value
) {
validateConfirmPassword();
}
}
);
password.addEventListener(
"blur",
validatePassword
);
confirmPassword.addEventListener(
"input",
() => {
if (
confirmPassword.value
) {
validateConfirmPassword();
} else {
clearFieldState(
confirmPassword
);
}
}
);
confirmPassword.addEventListener(
"blur",
validateConfirmPassword
);
firstName.addEventListener(
"blur",
() => {
validateName(
firstName,
"First name"
);
}
);
lastName.addEventListener(
"blur",
() => {
validateName(
lastName,
"Last name"
);
}
);
username.addEventListener(
"blur",
validateUsername
);
role.addEventListener(
"change",
validateRole
);
/* ==================================================
BIO COUNTER
================================================== */
bio.addEventListener(
"input",
() => {
bioCount.textContent =
String(
bio.value.length
);
}
);
/* ==================================================
TERMS
================================================== */
terms.addEventListener(
"change",
() => {
if (terms.checked) {
termsError.textContent = "";
}
}
);
/* ==================================================
COMPLETE REGISTRATION
================================================== */
const completeRegistration = () => {
/*
* Terms must be accepted.
*/
if (!terms.checked) {
termsError.textContent =
"Please accept the Terms of Service and Privacy Policy.";
return;
}
termsError.textContent = "";
/*
* Update data one last time.
*/
updateReview();
/*
* Hide wizard.
*/
form.hidden = true;
if (progress) {
progress.hidden = true;
}
if (header) {
header.hidden = true;
}
/*
* Show success state.
*/
success.hidden = false;
};
/* ==================================================
CREATE ACCOUNT BUTTON
Direct click handler
================================================== */
submitBtn.addEventListener(
"click",
(event) => {
event.preventDefault();
event.stopPropagation();
completeRegistration();
}
);
/* ==================================================
FORM SUBMIT FALLBACK
================================================== */
form.addEventListener(
"submit",
(event) => {
event.preventDefault();
completeRegistration();
}
);
/* ==================================================
RESTART
================================================== */
restartBtn.addEventListener(
"click",
(event) => {
event.preventDefault();
/*
* Reset form data.
*/
form.reset();
/*
* Remove validation states.
*/
formSteps.forEach((step) => {
const fields = [
...step.querySelectorAll(
".cr-field"
)
];
fields.forEach((field) => {
field.classList.remove(
"cr-field--error",
"cr-field--valid"
);
const error =
field.querySelector(
".cr-field__error"
);
if (error) {
error.textContent = "";
}
});
});
/*
* Reset terms.
*/
termsError.textContent = "";
/*
* Reset bio counter.
*/
bioCount.textContent = "0";
/*
* Reset password meter.
*/
passwordStrength.removeAttribute(
"data-strength"
);
passwordStatus.textContent =
"Password strength";
/*
* Reset password visibility.
*/
password.type = "password";
if (passwordToggle) {
passwordToggle.setAttribute(
"aria-label",
"Show password"
);
}
/*
* Restore wizard.
*/
success.hidden = true;
form.hidden = false;
if (progress) {
progress.hidden = false;
}
if (header) {
header.hidden = false;
}
/*
* Return to Step 1.
*/
showStep(1);
}
);
/* ==================================================
INITIAL STATE
================================================== */
success.hidden = true;
showStep(1);
})();
How This Multi Step Registration Form Works
The Multi Step Registration Form divides account creation into three stages: Account, Profile, and Review. The HTML keeps each stage inside a .cr-form-step section, while data-step attributes identify which section belongs to each step. Only the section with .cr-form-step--active is displayed, so users see one part of the registration process at a time.
The progress area uses three step indicators connected by lines. JavaScript tracks the current position with the currentStep variable and updates the indicators whenever showStep() runs. Completed steps receive .cr-step--complete, the current one receives .cr-step--active, and completed connecting lines use .cr-step__line--complete. CSS animates each line with transform: scaleX() and a 0.4s transition.
Step one collects an email address, password, and password confirmation. JavaScript validates the email with a regular expression, requires passwords to contain at least eight characters, and checks that both password fields match. The password strength meter calculates a score from length, uppercase letters, numbers, and special characters. Its four bars then change state through the data-strength attribute.
The password field also includes a visibility button. Its click listener switches the input type between password and text and updates the button’s aria-label. For more information about this browser behavior, see the MDN input element documentation.
Step two collects the first and last name, username, role, and an optional bio. Names need at least two characters, while usernames need at least three and can contain only letters, numbers, and underscores. The bio uses a maxlength of 160, with an input event updating the visible character counter as the user types.
Before moving forward, the Next Step button validates the fields belonging to the current stage. Invalid fields receive .cr-field--error, while valid inputs receive .cr-field--valid. This prevents users from reaching later stages until the required information passes the component’s checks.
Step three builds a review from the entered values. updateReview() fills elements marked with data-review, combines the first and last names, adds @ before the username, displays the selected role text, and masks the password with dots. Edit buttons can return directly to steps one or two.
Submitting requires the terms checkbox. Once accepted, the component hides the form, header, and progress area and displays the success state. The Start Again button calls form.reset(), clears validation classes, resets the password meter and bio counter, restores password hiding, and returns the wizard to step one.
CSS gives the form a dark interface with purple and cyan accents. The main card has a 1180px maximum width and 24px border radius. Desktop layouts use two-column CSS Grid arrangements where appropriate, while breakpoints at 850px, 650px, and 400px progressively simplify the layout for smaller screens.
Customizing the Multi Step Registration Form
Most visual changes can be handled through the CSS custom properties near the start of .cr-step-form, while field limits and available choices can be adjusted in the HTML and JavaScript.
- Change
--cr-bg,--cr-panel, and--cr-fieldto adjust the dark background and field surfaces. - Edit
--cr-purple,--cr-cyan,--cr-green, and--cr-dangerto create a different accent, success, and validation palette. - Change the card’s
max-width: 1180px, padding, or24pxborder radius to adjust its overall proportions. - Adjust the password’s eight-character minimum in both the HTML
minlengthand JavaScript validation logic. - Modify the options inside
#crRoleto provide different user roles. - Change the bio’s
maxlength="160"and corresponding counter display if a different limit is needed. - Edit the
650pxand400pxmedia queries to control when the desktop grid changes to the mobile layout.
Where to Use This Multi Step Registration Form
This component works best when registration needs several pieces of information but presenting every field at once would make the interface crowded.
- Account creation pages that require login and profile details.
- Developer or community platforms where users choose a role during signup.
- Membership websites with an account review stage before submission.
- SaaS onboarding flows that need structured profile information.
- Portfolio or creator platforms that collect usernames and short bios.
- Demo projects that need client-side form validation and multi-step navigation.
The component is a front-end demo: its completion function displays a success state rather than sending registration data to a server. For another account interface with separate login and signup views, the 3D Flip Login & Signup Form is a related CodeRipple component.
Frequently Asked Questions
Does this form validate each step before continuing?
Yes. Step one checks the email, password, and password confirmation, while step two validates the first name, last name, username, and role. The Next Step button stops navigation when those checks fail.
How does the password strength indicator work?
JavaScript awards one point each for having at least eight characters, an uppercase letter, a number, and a special character. The resulting score controls the four visual strength bars and labels such as Weak, Fair, Good, and Strong.
Does the form actually create a user account?
No. The current JavaScript does not send data to a server or registration API. After the terms checkbox is accepted, it hides the wizard and displays the built-in demo success message.
Is the Multi Step Registration Form responsive?
Yes. CSS media queries adjust the card, progress indicator, review grid, fields, and navigation controls. At widths below 650px, the two-column form layouts become single-column layouts, and additional adjustments are applied below 400px.
This Multi Step Registration Form combines staged navigation, client-side validation, progress feedback, review controls, responsive layouts, and a resettable success state in one self-contained registration interface.
