An inline validation login form built with pure HTML and CSS that displays validation feedback directly within the input field area. It enhances error visibility and real time input clarity without requiring JavaScript.
Usage
Use this component when interfaces require immediate input feedback, such as login forms, registration flows, onboarding screens, or authentication panels that benefit from clear validation messaging.
Implementation
The layout is implemented using CSS pseudo classes like :valid and :invalid combined with conditional styling, allowing inputs to visually reflect validation states. Responsive styling ensures consistent alignment across screen sizes.
HTML
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Login</title>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700&family=DM+Sans:wght@300;400;500&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="login-style.css" />
</head>
<body>
<div class="card">
<div class="header">
<p class="eyebrow">Welcome back</p>
<h1 class="title">Sign in</h1>
<p class="subtitle">Access your account to continue</p>
</div>
<form novalidate>
<!-- Email field -->
<div class="field">
<label class="field-label" for="email">Email</label>
<div class="field-wrap">
<input
class="field-input"
type="email"
id="email"
name="email"
placeholder="you@example.com"
required
autocomplete="email"
/>
<span class="field-icon" aria-hidden="true">
<svg class="icon-check" width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M3 8l3.5 3.5L13 5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<svg class="icon-x" width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
</svg>
</span>
<span class="field-msg field-msg--hint">Enter a valid email address</span>
<span class="field-msg field-msg--error">Please enter a valid email address</span>
</div>
</div>
<!-- Password field -->
<div class="field">
<label class="field-label" for="password">Password</label>
<div class="field-wrap">
<input
class="field-input"
type="password"
id="password"
name="password"
placeholder="Min. 8 characters"
required
minlength="8"
autocomplete="current-password"
/>
<span class="field-icon" aria-hidden="true">
<svg class="icon-check" width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M3 8l3.5 3.5L13 5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<svg class="icon-x" width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
</svg>
</span>
<span class="field-msg field-msg--hint">At least 8 characters</span>
<span class="field-msg field-msg--error">Password must be at least 8 characters</span>
</div>
</div>
<!-- Remember me -->
<label class="checkbox-row">
<input class="checkbox-input" type="checkbox" name="remember" />
<span class="checkbox-label">Keep me signed in for 30 days</span>
</label>
<!-- Submit -->
<button class="btn" type="submit">Sign in</button>
</form>
<div class="divider"><span>or</span></div>
<p class="form-footer">
Don't have an account? <a href="#">Create one</a>
·
<a href="#">Forgot password?</a>
</p>
</div>
</body>
</html>CSS
*::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--bg: #0c0c0e;
--surface: #141416;
--border: #2a2a2e;
--border-focus: #c8a96e;
--border-valid: #4caf7d;
--border-invalid: #e05c5c;
--text: #f0ede8;
--muted: #7a7870;
--accent: #c8a96e;
--accent-hover: #dfc08a;
--valid: #4caf7d;
--invalid: #e05c5c;
--valid-bg: rgba(76, 175, 125, 0.06);
--invalid-bg: rgba(224, 92, 92, 0.06);
}
body {
background-color: var(--bg);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
font-family: 'DM Sans', sans-serif;
color: var(--text);
padding: 2rem;
position: relative;
overflow: hidden;
}
/* Ambient background decoration */
body::before {
content: '';
position: fixed;
width: 600px;
height: 600px;
border-radius: 50%;
background: radial-gradient(circle, rgba(200,169,110,0.06) 0%, transparent 70%);
top: -200px;
right: -200px;
pointer-events: none;
}
body::after {
content: '';
position: fixed;
width: 400px;
height: 400px;
border-radius: 50%;
background: radial-gradient(circle, rgba(76,175,125,0.04) 0%, transparent 70%);
bottom: -100px;
left: -100px;
pointer-events: none;
}
.card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 2px;
padding: 3rem 3.5rem;
width: 100%;
max-width: 440px;
position: relative;
animation: fadeUp 0.6s ease both;
}
/* Top gold accent line */
.card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, transparent, var(--accent), transparent);
}
@keyframes fadeUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
/* ── Header ── */
.header {
margin-bottom: 2.5rem;
}
.eyebrow {
font-size: 0.65rem;
font-weight: 500;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--accent);
margin-bottom: 0.75rem;
}
.title {
font-family: 'Playfair Display', serif;
font-size: 2.2rem;
font-weight: 700;
color: var(--text);
line-height: 1.1;
letter-spacing: -0.02em;
}
.subtitle {
font-size: 0.85rem;
color: var(--muted);
margin-top: 0.6rem;
line-height: 1.5;
}
/* ── Field Group ── */
.field {
margin-bottom: 1.4rem;
}
.field-label {
display: block;
font-size: 0.72rem;
font-weight: 500;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--muted);
margin-bottom: 0.5rem;
transition: color 0.2s;
}
.field-wrap {
position: relative;
}
.field-input {
display: block;
width: 100%;
background: var(--bg);
border: 1px solid var(--border);
border-radius: 2px;
padding: 0.85rem 2.8rem 0.85rem 1rem;
font-family: 'DM Sans', sans-serif;
font-size: 0.9rem;
color: var(--text);
outline: none;
transition: border-color 0.2s, background 0.2s, box-shadow 0.2s;
}
.field-input::placeholder {
color: var(--muted);
opacity: 0.5;
}
/* Focus state */
.field-input:focus {
border-color: var(--border-focus);
box-shadow: 0 0 0 3px rgba(200,169,110,0.12);
}
/* Valid / Invalid via :user-valid / :user-invalid (CSS-only) */
.field-input:user-valid {
border-color: var(--border-valid);
background: var(--valid-bg);
}
.field-input:user-invalid {
border-color: var(--border-invalid);
background: var(--invalid-bg);
}
/* Status icon slot */
.field-icon {
position: absolute;
right: 0.9rem;
top: 50%;
transform: translateY(-50%);
width: 18px;
height: 18px;
pointer-events: none;
opacity: 0;
transition: opacity 0.2s;
}
/* Show check when valid */
.field-input:user-valid ~ .field-icon .icon-check { display: block; }
.field-input:user-valid ~ .field-icon .icon-x { display: none; }
.field-input:user-valid ~ .field-icon { opacity: 1; }
/* Show × when invalid */
.field-input:user-invalid ~ .field-icon .icon-check { display: none; }
.field-input:user-invalid ~ .field-icon .icon-x { display: block; }
.field-input:user-invalid ~ .field-icon { opacity: 1; }
.icon-check { color: var(--valid); display: none; }
.icon-x { color: var(--invalid); display: none; }
/* Validation messages */
.field-msg {
font-size: 0.75rem;
margin-top: 0.45rem;
padding-left: 0.1rem;
line-height: 1.4;
display: none;
}
.field-msg--error { color: var(--invalid); }
.field-msg--hint { color: var(--muted); }
/* Show error on invalid */
.field-input:user-invalid ~ .field-msg--error { display: block; }
/* Show hint on focus when field is empty */
.field-input:focus:placeholder-shown ~ .field-msg--hint { display: block; }
/* Hide hint once valid/invalid state is set */
.field-input:user-valid ~ .field-msg--hint { display: none; }
.field-input:user-invalid ~ .field-msg--hint { display: none; }
/* ── Checkbox ── */
.checkbox-row {
display: flex;
align-items: center;
gap: 0.65rem;
margin-bottom: 2rem;
cursor: pointer;
}
.checkbox-input {
appearance: none;
width: 16px;
height: 16px;
flex-shrink: 0;
border: 1px solid var(--border);
border-radius: 2px;
background: var(--bg);
cursor: pointer;
transition: border-color 0.2s, background 0.2s;
position: relative;
}
.checkbox-input:checked {
background: var(--accent);
border-color: var(--accent);
}
.checkbox-input:checked::after {
content: '';
position: absolute;
left: 4px;
top: 1px;
width: 5px;
height: 9px;
border: 2px solid #0c0c0e;
border-top: none;
border-left: none;
transform: rotate(45deg);
}
.checkbox-label {
font-size: 0.8rem;
color: var(--muted);
user-select: none;
}
.checkbox-label a {
color: var(--accent);
text-decoration: none;
}
.checkbox-label a:hover { text-decoration: underline; }
/* ── Submit Button ── */
.btn {
display: block;
width: 100%;
padding: 0.95rem;
background: var(--accent);
color: #0c0c0e;
font-family: 'DM Sans', sans-serif;
font-size: 0.8rem;
font-weight: 600;
letter-spacing: 0.14em;
text-transform: uppercase;
border: none;
border-radius: 2px;
cursor: pointer;
transition: background 0.2s, transform 0.15s, box-shadow 0.2s;
}
.btn:hover {
background: var(--accent-hover);
transform: translateY(-1px);
box-shadow: 0 8px 24px rgba(200,169,110,0.2);
}
.btn:active {
transform: translateY(0);
box-shadow: none;
}
/* ── Footer ── */
.form-footer {
text-align: center;
margin-top: 1.8rem;
font-size: 0.8rem;
color: var(--muted);
}
.form-footer a {
color: var(--accent);
text-decoration: none;
}
.form-footer a:hover { text-decoration: underline; }
/* ── Divider ── */
.divider {
display: flex;
align-items: center;
gap: 1rem;
margin: 1.8rem 0;
}
.divider::before,
.divider::after {
content: '';
flex: 1;
height: 1px;
background: var(--border);
}
.divider span {
font-size: 0.7rem;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--muted);
}Notes
- Built with pure HTML and CSS
- No JavaScript required
- Uses native validation state styling
- Enhances real time input feedback clarity
- Fully responsive across breakpoints
- Suitable for forms and authentication screens
- Easy to customize validation colors and indicators
Preview styles shown. Production customization recommended.
Browse More UI Components
Explore hundreds of reusable HTML & CSS UI components built for modern web projects.
Discover buttons, cards, loaders, animations, layouts, and more all with live previews and clean, copy-paste code.
