<div class="KickInput">
  <input type="text" class="KickInput-input" />
  <label class="KickInput-label">
    First Name
  </label>
  <svg width="300px" height="42px" viewBox="0 0 80 42" class="KickInput-svg">
    <path 
      class="KickInput-kicker" 
      d="M0,40 C16,40 50,40 80,40 L300,40" 
      stroke="#C9CBCE" 
      stroke-width="4" 
      stroke-linecap="round"
      fill="none"
    />
  </svg>
</div>


<div class="Info">
  Read more about front end development  on <a target="_blank" href="https://stanko.github.io">my blog</a>.
  
  <br/><br/>
  
  Inspired by <a target="_blank" href="https://uimovement.com/ui/5963/input/">this mockup</a>.
</div>
// Inspired by this mockup
// https://uimovement.com/ui/5963/input/

body {
  padding: 100px 10px;
  font-family: Helvetica, Arial, sans-serif;
  font-size: 20px;
}

input {
  font-family: Helvetica, Arial, sans-serif;
  font-size: 20px;
}

svg {
  overflow: visible; 
}

.KickInput {
  height: 60px;
  width: 300px;
  position: relative;
  margin: 0 auto;
}

.KickInput-svg {
  height: 42px;
  width: 80px;
  display: block;
  position: absolute;
  bottom: 0;
  left: 0;
  z-index: 0;
}

.KickInput-kicker {
  transition: stroke 500ms;
  
  .KickInput-input:focus + label + svg & {
    stroke: #3978F7;
  }
}

.KickInput-input {
  height: 60px;
  width: 300px;
  display: block;
  position: relative;
  z-index: 10;
  border: 0;
  background: none;
  outline: 0;
  Color: #232428;
}

.KickInput-label {
  position: absolute;
  bottom: 14px;
  left: 0;
  transition: transform 250ms cubic-bezier(0.145, 1.625, 0.715, 1.515), color 250ms;
  transform-origin: top left;
  color: #C9CBCE;
  
  .KickInput-input:focus + &,
  .KickInput-input--hasValue + & {
    transform: translateY(-35px) scale(0.7);
  }
  
  .KickInput-input:focus + & {
    color: #3978F7;
  }
}

svg {
  display: block;
}


// Info

.Info {
  text-align: center;
  margin-top: 100px;
  color: rgba(black, 0.2);
  font-size: 14px;
  line-height: 22px;
  
  a {
    color: rgba(black, 0.2);
    text-decoration: none;
    border-bottom: thin solid rgba(black, 0.2);
    
    &:hover {
      color: rgba(black, 0.3);
      border-bottom-color: rgba(black, 0.3);
    }
  }
}

  
View Compiled
// M0,40 C16,40
// M5,20 C16,35
// M10,0 C16,30
//  a b      c
// a  0 - 10
// b 40 -  0
// c 40 - 30

const endOfPath = '50,40 80,40 L300,40';

const aStart = 0;
const aEnd = 10;

const bStart = 40;
const bEnd = 0;

const cStart = 40;
const cEnd = 30;

const aStep = 1.1;
const bStep = -4 * aStep;
const cStep = -aStep;

let a = aStart;
let b = bStart;
let c = cStart;

const kicker = document.querySelector('.KickInput-kicker');
const input = document.querySelector('.KickInput-input');

const FRAME_DURATION = 16.66; // 60fps
// If available we are using native "performance" API instead of "Date"
// Read more about it on MDN:
// https://developer.mozilla.org/en-US/docs/Web/API/Performance
const getTime = typeof performance === 'function' ? performance.now : Date.now;

// Initial time
let lastUpdate = null;

let direction = 1;

let stop = false;

function animate() {
  const now = getTime();
  // This is the main part
  // We are checking how much time has passed since the last update
  // and translating that to frames
  const delta = (now - lastUpdate) / FRAME_DURATION;

  // Updating scene logic
  a += aStep * delta * direction;
  b += bStep * delta * direction;
  c += cStep * delta * direction;
  
  if (a > aEnd) {
    // Reverse direction
    direction = -1;
    a = aEnd;
    b = bEnd;
    c = cEnd;
  } else if (a < aStart && direction === -1) { 
    // Stop animation
    stop = true;
    direction = 1;
    a = aStart;
    b = bStart;
    c = cStart;
  }

  // Render updated scene
  kicker.setAttribute('d', `M${ a },${ b } C16,${ c } ${ endOfPath }`);
  
  // Update last updated time
  lastUpdate = now;

  if (!stop) {
    requestAnimationFrame(animate);
  }
}

input.addEventListener('focus', () => {
  lastUpdate = getTime();
  stop = false;
  
  if (input.value.trim() === '') {
    animate();
  }
});

input.addEventListener('blur', () => {
  if (input.value.trim() === '') {
    input.setAttribute('class', 'KickInput-input');
  } else {
    input.setAttribute('class', 'KickInput-input KickInput-input--hasValue');
  }
});
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.