AI CSS Animations

Password Typing Animation

Each character shows for a moment and then turns into a dot, the way phone keyboards mask passwords, while a strength meter fills and its label climbs from Weak to Strong.

Also known as: password field animation css, masked input typing, password strength meter animation.

HTML

<div class="txt-password-typing" aria-label="Password, strength: strong">
  <span class="txt-password-typing-field" aria-hidden="true"><span style="--i: 0"><b>s</b></span><span style="--i: 1"><b>u</b></span><span style="--i: 2"><b>n</b></span><span style="--i: 3"><b>f</b></span><span style="--i: 4"><b>l</b></span><span style="--i: 5"><b>o</b></span><span style="--i: 6"><b>w</b></span><span style="--i: 7"><b>e</b></span><span style="--i: 8"><b>r</b></span><span style="--i: 9"><b>7</b></span></span>
  <span class="txt-password-typing-meter" aria-hidden="true">
    <span class="txt-password-typing-bars"><i style="--t: 0.48s"></i><i style="--t: 1.02s"></i><i style="--t: 1.56s"></i><i style="--t: 1.92s"></i></span>
    <span class="txt-password-typing-label"><em style="--a: 0.48s; --b: 1.02s">Weak</em><em style="--a: 1.02s; --b: 1.56s">Fair</em><em style="--a: 1.56s; --b: 1.92s">Good</em><em style="--a: 1.92s">Strong</em></span>
  </span>
</div>

CSS

.txt-password-typing {
  --c: var(--txt-color, #3b82f6);
  font-size: var(--txt-size, 32px);
  font-family: system-ui, sans-serif;
  font-weight: 700;
  line-height: 1.2;
  display: inline-grid;
  gap: 0.5em;
  width: 9.5em;
  font-size: calc(var(--txt-size, 32px) * 0.7);
  font-weight: 600;
  text-align: left;}
.txt-password-typing-field {
  display: flex;
  align-items: center;
  height: 2em;
  padding: 0 0.8em;
  border-radius: 0.45em;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  background: color-mix(in srgb, currentColor 5%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, currentColor 18%, transparent);
}
.txt-password-typing-field span {
  position: relative;
  display: inline-block;
  width: 1.1ch;
  text-align: center;
}
/* the typed letter shows briefly... */
.txt-password-typing-field b {
  font-weight: inherit;
  animation: txt-password-typing-char 0.55s ease-out calc(0.3s + var(--i) * 0.18s) both;
}
/* ...then a dot takes its place */
.txt-password-typing-field span::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0.42em;
  height: 0.42em;
  margin: -0.21em 0 0 -0.21em;
  border-radius: 50%;
  background: currentColor;
  animation: txt-password-typing-dot 0.2s ease-out calc(0.7s + var(--i) * 0.18s) both;
}
.txt-password-typing-meter {
  display: flex;
  align-items: center;
  gap: 0.6em;
  font-size: 0.75em;
}
.txt-password-typing-bars {
  display: flex;
  flex: 1;
  gap: 0.25em;
}
.txt-password-typing-bars i {
  flex: 1;
  height: 0.3em;
  border-radius: 0.15em;
  background: color-mix(in srgb, currentColor 14%, transparent);
  animation: txt-password-typing-bar 0.25s ease-out var(--t) forwards;
}
.txt-password-typing-label {
  display: grid;
  width: 3.4em;
  color: var(--c);
}
.txt-password-typing-label em {
  grid-area: 1 / 1;
  font-style: normal;
  visibility: hidden;
  animation: txt-password-typing-label calc(var(--b) - var(--a)) step-end var(--a);
}
.txt-password-typing-label em:last-child {
  animation: txt-password-typing-stay 0s var(--a) forwards;
}
@keyframes txt-password-typing-char {
  0% { opacity: 0; transform: translateY(0.3em); }
  25%, 70% { opacity: 1; transform: none; }
  100% { opacity: 0; transform: scale(0.4); }
}
@keyframes txt-password-typing-dot {
  from { opacity: 0; transform: scale(0.2); }
}
@keyframes txt-password-typing-bar {
  to { background: var(--c); }
}
@keyframes txt-password-typing-label {
  0%, 100% { visibility: visible; }
}
@keyframes txt-password-typing-stay {
  to { visibility: visible; }
}

@media (prefers-reduced-motion: reduce) {
  .txt-password-typing, .txt-password-typing *, .txt-password-typing::before, .txt-password-typing::after, .txt-password-typing *::before, .txt-password-typing *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

Customizing this snippet

  • Color: set --txt-color on the element or a parent. Currently previewing #3b82f6.
  • Font size: set --txt-size. Every other dimension is in em, so the whole thing scales together. Currently previewing 40px.
  • Speed: change the duration on the transition or animation shorthand. Staggered delays are relative, so they keep their rhythm.
  • Reduced motion: the rule at the end of the CSS turns the motion off for people who asked their OS for less of it. Keep it.

Similar text animations