DEV Community

Cover image for Pure CSS Focus Follower
Prahalad S
Prahalad S

Posted on

Pure CSS Focus Follower

Pure CSS Focus Follower

Overview
This CSS module creates a visual effect where a single circular element (.follow) moves to follow the currently focused or checked form element (text inputs, checkboxes, or submit button) in a form. When the submit button is clicked, the circle moves in an arc-like path to enhance the visual transition. The effect is implemented purely in CSS, without JavaScript, and is designed to match the behavior of a provided JavaScript-based example where a circle stops 16px to the left of the focused element, vertically centered.

Purpose

  • Provide an interactive, visually engaging user experience by highlighting the active form element with a moving circle.
  • Ensure the circle follows clicks on text inputs, checkboxes (both :focus and :checked states), and the submit button.

HTML

  <h2>Focus Follower in {PURE CSS}</h2>
<div class="form-wrapper">
  <form onsubmit="return false;">
    <label for="name">Name</label>
    <input type="text" id="name">

    <label for="email">Email</label>
    <input type="email" id="email">

    <label for="password">Password</label>
    <input type="password" id="password">
    <input type="checkbox" id="check1">
    <label for="check1">I accept the terms</label>
    <button>Submit</button>
    <span class="follow"></span>
  </form>
</div>
Enter fullscreen mode Exit fullscreen mode

CSS

* {
  box-sizing: border-box;
}

:root {
  --spacing: 16px;
  --radius: 8px;
}

html,
body {
  font-family: "Source Code Pro", Inconsolata, Menlo, monospace;
  font-size: 20px;
  display: flex;
  flex-direction:column;
  align-items: center;
  justify-content: center;
  height: 100%;
  margin: 0;
  color: #fff;
  background-color: cadetblue;
}

.form-wrapper {
  position: relative;
  height: 500px;
  width: 500px;
  padding: 80px;
  border: 1px dashed #becdcd;
  margin: 0 auto;
}

form {
  margin: auto;
  width: 100%;
  max-width: 400px;
  position: relative;
}

label {
  color: #fff;
}

input[type="text"],
input[type="email"],
input[type="password"] {
  display: block;
  width: 100%;
  margin: 0.5rem 0 1rem 0;
  padding: 0.5rem;
  font-size: 1rem;
  border: 0;
  border-radius: 0.125rem 0.25rem;
  background-color: hsl(222, 20%, 95%);
  position: relative;
}

input[type="checkbox"] {
  margin: 0 0.5rem 0 0;
  width: 1rem;
  height: 1rem;
}

button {
  display: block;
  padding: 0.5rem 1rem;
  border: 0;
  border-radius: 0.125rem 0.25rem;
  background-color: darkslategrey;
  color: #fff;
  margin: 2rem 0 0 auto;
  position: relative;
}

input:focus,
button:focus {
  outline: 0;
}

/* Follower element styling */
.follow {
  position: absolute;
  width: calc(var(--radius) * 2);
  height: calc(var(--radius) * 2);
  background-color: darkslategrey;
  border-radius: 50%;
  pointer-events: none;
  z-index: 1;
  opacity: 0;
  transition: transform 0.3s ease, opacity 0.2s ease;
  transform: translateX(0) translateY(0);
  left: 0;
  top: 0;
}

/* Position follower for each focused or checked element */
#name:focus ~ .follow {
  transform: translateX(calc(-1 * var(--spacing) - var(--radius)))
    translateY(2.35rem);
  opacity: 1;
}

#email:focus ~ .follow {
  transform: translateX(calc(-1 * var(--spacing) - var(--radius)))
    translateY(7.25rem);
  opacity: 1;
}

#password:focus ~ .follow {
  transform: translateX(calc(-1 * var(--spacing) - var(--radius)))
    translateY(12rem);
  opacity: 1;
}

#check1:focus ~ .follow,
#check1:checked ~ .follow {
  transform: translateX(calc(-1 * var(--spacing) - var(--radius)))
    translateY(14.5rem);
  opacity: 1;
}

button:focus ~ .follow {
  transform: translateX(calc(-1 * var(--spacing) - var(--radius) + 12.8rem))
    translateY(18.15rem);

  opacity: 1;
}

Enter fullscreen mode Exit fullscreen mode

WORKING DEMO

Top comments (0)