Aller au contenu principal
Guillaume Duverger Code & graphisme

Form validation avec pseudo-classe :has()

Votre navigateur ne supporte pas cette démonstration

Votre navigateur ne supporte pas les transitions discrètes

Veuillez entrer une adresse valide
Votre mot de passe doit contenir au moins 8 caractères



<form>
	
<div class=cadre-input>
<label for="email">Email :</label>
<div class=input-form>
<svg></svg>
<input required type="email" id="email" title="Veuillez entrer une adresse valide" placeholder="Veuillez entrer une adresse valide">
</div>
<div class="erreur"><span>Veuillez entrer une adresse valide</span></div>
</div>
	
<div class=cadre-input>

<label for="password">Mot de passe :</label>
<div class=input-form>
<svg>...</svg>
<input required type="password" id="password"  placeholder="Votre mot de passe" title="Votre mot de passe doit contenir au moins 8 caractères" pattern=".{8,}">
</div>	
<div class="erreur"><span>Votre mot de passe doit contenir au moins 8 caractères</span></div>
</div>
	
<button type="submit">Se connecter</button>
	
</form>







*{box-sizing: border-box}

:root {
	
  --rouge: oklch(48% .25 30);
  --vert: oklch(51% 0.18 145.47);
  --jaune: color-mix(in oklch,var(--vert),var(--blanc));
  --vert-1: oklch(71% 0.1 145.47);
  --gris: oklch(65% 0 0);
  --blanc:oklch(1 0 0);
  --texte: oklch(52% 0 0);
  --transition: 0.25s;
  
}



form {
	
display: grid;
grid-template-columns: auto minmax(30ch,1fr);
max-width: 75ch;
margin: 20rem auto;
gap: 1rem;
overflow:hidden	
}


.cadre-input {
	
--color: var(--texte);
grid-column: span 2;
display: grid;
gap: 1rem;
grid-template-columns: subgrid;
grid-template-rows: auto 3rem;
align-items: center;

	
}
	

form label {
display: flex;
font-weight: bold;
color: var(--color);
font-size: 1.125rem;

}
	
form input {

border: 2px solid var(--color);
border-radius: 4px;
height: 3rem;
padding-left:3.5rem;
font-weight: 400;

}

form input:is(:focus-within,:focus-visible){
  
outline:2px solid var(--color);
outline-offset: 2px
}

form input::placeholder {

  color: transparent;
}

[type="submit"] {
	
place-self:center;
grid-column: span 2;
padding: 1rem 2rem;
border-radius: 4px;
border: 0;
cursor: pointer;
background:linear-gradient(to right,var(--step,var(--gris)) 50%,var(--gris) 50%);
font-weight: bold;
font-size: 1.125rem;
color: var(--color);


}

.input-form{
	
	display: grid;
	
	}
	
.input-form>*{
	
	grid-area:1/1
	
	}
	
.input-form svg{
	
	border-radius: 4px;
	margin-left:.5rem;
	width:2.5rem;
	height:2.5rem;
	fill:var(--color);
	z-index:1;
	align-self:center
	
	}
	
		
.cadre-input:has(:invalid) {
	
  --color: var(--rouge);
	
}

.cadre-input:has(:focus) {
	
  --color: var(--jaune);
	
}

.cadre-input:has(:valid) {
	
  --color: var(--vert);
}

.cadre-input:has(:placeholder-shown) {
	
  --color: var(--texte);
}
		
.erreur {
	
display: none;
translate:0 10px;
opacity:0;
white-space: nowrap;
font-size: 1rem;
grid-column:span 2;

}
	
.erreur span {
 
position: relative;
background-color: var(--rouge);
border-radius: 5px;
padding: 1rem;
color:var(--blanc);
text-align: center;
}
	
.erreur span::after {
	 
  content: "";
  position: absolute;
  top: -5px;
  right: 10%;
  width: 0;
  height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-bottom: 5px solid var(--rouge);

}
	

	
.cadre-input:first-of-type:has(:valid) ~ [type="submit"]{ 
	
	--step:var(--vert);
	--gris:var(--vert-1)
	}

.cadre-input:has(:valid) ~ .cadre-input:last-of-type:has(:valid) ~ [type="submit"] {
	
	--gris:var(--vert);
	color:var(--blanc)
	
	}
	
.cadre-input:has(:invalid:not(:focus):not(:placeholder-shown)) .erreur {
	
display: block;
translate:0 0;  
opacity:1;
	
	}	
	
	
	
@media (prefers-reduced-motion: no-preference) {

form input{transition: border-color var(--transition);}
form label{transition: color var(--transition);}
	
.cadre-input:has(:invalid:not(:focus):not(:placeholder-shown)) .erreur {
	

transition:opacity var(--transition), translate var(--transition), display var(--transition)
	
}
	
@starting-style {.cadre-input:has(:invalid:not(:focus):not(:placeholder-shown)) .erreur{
	
	opacity:0;
	translate:0 10px;
	}
	
	}	
	}