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 mais cela n'empêche pas la démonstration de fonctionner.

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;
	}
	
	}	
	}