Building Controls By using HTML, CSS & JS



 




Buliding HTML Structure
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Controls</title>
    <link rel="stylesheet" href="style.css" />
    <link rel="preconnect" href="https://fonts.googleapis.com" />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    <link
      href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap"
      rel="stylesheet"
    />
    <link
      rel="stylesheet"
      href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0"
    />
  </head>
  <body>
    <div class="textbox">
      <input
        oninput="handleChange(event)"
        onkeydown="handleStartTyping()"
        autocomplete="off"
        id="input"
        type="text"
      />
      <span class="icon visible material-symbols-outlined">account_circle</span>
      <label htmlFor="input">Username</label>
      <span class="spinner"></span>
    </div>
    <button disabled>
      <p>Sign up</p>
      <span class="material-symbols-outlined"> arrow_right_alt </span>
    </button>
    <script type="text/javascript" src="script.js"></script>
  </body>
</html>
Styling CSS
    body {
    margin: 0;
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    background: #151515;
    font-family: "Euclid Circular A", "Poppins";
  }
  
  * {
    box-sizing: border-box;
  }
  
  .textbox {
    position: relative;
    margin-bottom: 16px;
  }
  
  .textbox :is(label, span) {
    position: absolute;
    top: 50%;
    translate: 0 -50%;
    pointer-events: none;
    color: #888888;
    transition: 0.3s;
  }
  
  .textbox > label {
    left: 44px;
    translate: 0 -50%;
    padding: 4px 8px;
  }
  
  .textbox > .icon {
    z-index: 2;
    left: 16px;
    font-size: 26px;
  }
  
  .textbox > input {
    height: 56px;
    width: 240px;
    padding-left: 48px;
    border: 2px solid #292929;
    border-radius: 8px;
    outline: none;
    background: transparent;
    color: #f9f9f9;
    font-family: inherit;
    font-size: 16px;
    transition: 0.3s;
  }
  
  .textbox > input.valid.has-value {
    border-color: #14ca99;
  }
  
  .textbox > :is(input:focus, .has-value) {
    border-color: #d3d3d3;
  }
  
  .textbox > input.has-value {
    border-color: #ff5360;
  }
  
  .textbox > :is(input:focus, .has-value) ~ span {
    color: #f9f9f9;
  }
  
  .textbox > :is(input:focus, .has-value) ~ label {
    background: #151515;
    color: rgba(255, 255, 255, 0.75);
    translate: -42px -42px;
    scale: 0.8;
  }
  
  @keyframes spin {
    100% {
      rotate: 1turn;
    }
  }
  
  .spinner {
    position: absolute;
    top: 50%;
    right: 16px;
    translate: 0 -50%;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    border: 3px solid rgb(255 255 255 / 14%);
    border-top-color: #f7f7f7;
    opacity: 0;
    animation: spin 1s infinite linear;
  }
  
  .spinner.visible {
    opacity: 1;
  }
  
  button {
    width: 240px;
    height: 56px;
    border-radius: 6px;
    border: 0;
    font-family: inherit;
    font-size: 16px;
    display: flex;
    align-items: center;
    padding: 0 18px;
    justify-content: space-between;
    background: #2e3231;
    color: #f7f7f7;
    transition: 0.3s;
  }
  
  button:disabled {
    opacity: 0.33;
  }
      
JavaScript
  
const usernames = ["david", "david1", "david2"];

const input = document.querySelector("#input"),
  spinner = document.querySelector(".spinner"),
  button = document.querySelector("button");

const updateUi = (value) => {
  console.log("value", value);
  spinner.classList.remove("visible");

  const usernameExists = usernames.some((u) => u === value);

  console.log("usernames", usernames);
  console.log("usernameExists", usernameExists);

  const invalid = usernameExists || !value;

  button.disabled = invalid;
  input.classList.toggle("valid", !invalid);
};

const debounce = (callback, time) => {
  let interval;
  return (...args) => {
    clearTimeout(interval);
    interval = setTimeout(() => {
      callback.apply(null, args);
    }, time);
  };
};

const handleStartTyping = () => {
  spinner.classList.add("visible");
};

const handleChange = debounce((input) => {
  const { value } = input.target;

  console.log("input", input);

  input.target.classList.toggle("has-value", value);

  updateUi(value);
}, 500);
      

Post a Comment

0 Comments