0
\$\begingroup\$

The idea is to improve the usage of larger formulars. Done by adding a little animation to the input-elments.

When one of the textboxes is clicked or focussed via tab appears a colored border. Signalling the user which exact box has become active.

(function() {
  var inputs = document.querySelectorAll('input[type=text]');
  var userTriggered = true; // Avoiding recursion.

  inputs = Array.prototype.slice.call(inputs);

  inputs[0].focus();

  inputs.forEach(function(item) {

    item.addEventListener('focus', function() {
      if (userTriggered) {
        item.parentNode.focus(); // Trigger animation.

        setTimeout(function() {
          item.parentNode.blur(); // Remove the focus from the container.
          item.focus(); // Put the focus on the actual input-element.
          userTriggered = false;
        }, 600);
      } else {
        userTriggered = true;
      }
    });  
  });
})();
body {
  background: linear-gradient(90deg, #9c9c9c, #cfcfcf);
}

input[type=text] {
  font-family: georgia;
}

.wrap {
  margin: 25px auto;
  width: 850px;
}

.inputs-wrap {
  display: flex;
  justify-content: space-between;
}

fieldset {
  margin-bottom: 15px;
}

legend {
  font-size: 1.2rem;
  font-weight: 800;
  font-family: arial, sans-serif;
  margin-bottom: 10px;
  border-radius: 6px;
  letter-spacing: 1px;
}

.textbox, button {
  width: 180px;
  margin-right: getPercentage(20, 850px);
}

button:focus {
  opacity: 0.7;
}

.textbox:last-of-type {
  margin-right: 0;
}

.button-wrap {
  display: inline-block;
  position: relative;
}

.button-wrap:after, .button-wrap:before {
  content: "";
  display: inline-block;
  width: 0;
  height: 0;
  transition: all 0.6s;
  position: absolute;
}

.button-wrap:focus:after {
  width: 40%;
  height: 60%;
  border-left: 3px solid magenta;
  border-bottom: 3px solid magenta;
  bottom: 0;
  left: -3px;
}

.button-wrap:focus:before {
  width: 40%;
  height: 60%;
  border-right: 3px solid magenta;
  border-bottom: 3px solid magenta;
  bottom: 0;
  right: -3px;
}
<div class="wrap"> 
  <fieldset>
    <legend>Your personal data</legend>
    <div class="inputs-wrap">
      <div class="button-wrap" tabindex="1">
        <input type="text" class="hover-border textbox" placeholder="Please enter your first name" />  
      </div>

      <div class="button-wrap" tabindex="2">
        <input type="text" class="hover-border textbox" placeholder="Please enter your last name" /> 
      </div>

      <div class="button-wrap" tabindex="3">
        <input type="text" class="hover-border textbox" placeholder="Please enter your birthday" /> 
      </div> 

      <div class="button-wrap" tabindex="4">
        <input type="text" class="hover-border textbox" placeholder="Please enter your home town" /> 
      </div> 
    </div>
  </fieldset>
  
  <fieldset>
    <legend>Some numbers</legend>
    <div class="inputs-wrap">    
      <div class="button-wrap" tabindex="5">
        <input type="text" class="hover-border textbox" placeholder="Please enter one" />  
      </div>

      <div class="button-wrap" tabindex="6">
        <input type="text" class="hover-border textbox" placeholder="Please enter two" /> 
      </div>

      <div class="button-wrap" tabindex="7">
        <input type="text" class="hover-border textbox" placeholder="Please enter three" /> 
      </div> 

      <div class="button-wrap" tabindex="8">
        <input type="text" class="hover-border textbox" placeholder="Please enter your four" /> 
      </div> 
    </div>
  </fieldset>
  
  <fieldset>
    <legend>Some alphabet</legend>
    <div class="inputs-wrap">    
      <div class="button-wrap" tabindex="9">
        <input type="text" class="hover-border textbox" placeholder="Please enter A" />  
      </div>

      <div class="button-wrap" tabindex="10">
        <input type="text" class="hover-border textbox" placeholder="Please enter B" /> 
      </div>

      <div class="button-wrap" tabindex="11">
        <input type="text" class="hover-border textbox" placeholder="Please enter C" /> 
      </div>
      
      <div class="button-wrap" tabindex="12">
        <button>Send data</button> 
      </div>
    </div>
  </fieldset>
</div>

Here is the uncompiled Sass-code:

$primary-color: whitesmoke;
$wrap-width: 850px;
$marker-color: darken(magenta, 0);
$marker-duration: 0.6s;
$font-stack: arial, sans-serif;
$radius: 6px;

@mixin focusSettings($side) {
  width: 40%;
  height: 60%;  
  border-#{$side}: 3px solid $marker-color;
  border-bottom: 3px solid $marker-color;
  bottom: 0;
  #{$side}: -3px;
}

@function getPercent($value, $context) {
  @return percentage($value / $context);
}

body {
  background:
    linear-gradient( 90deg,
                     darken($primary-color, 35%),
                     darken($primary-color, 15%)
                   );
}

input[type=text] {
  font-family: georgia;
}

.wrap {
  margin: 25px auto;
  width: $wrap-width;
}

.inputs-wrap {
  display: flex;
  justify-content: space-between;
}

fieldset {
  margin-bottom: 15px;
}

legend {
  font-size: 1.2rem;
  font-weight: 800;
  font-family: $font-stack;
  margin-bottom: 10px;
  border-radius: $radius;
  letter-spacing: 1px;
}

.textbox, button {
  width: 180px;
  margin-right: getPercentage(20, $wrap-width);
}

button:focus {
  opacity: 0.7;
}

.textbox:last-of-type {
  margin-right: 0;
}

.button-wrap {
  display: inline-block;
  position: relative;
}
// Input[text] can't have an after- / before-
//   Pseudo-Element. Therefore an container
//   is needed.
.button-wrap:after, .button-wrap:before {
  content: "";
  display: inline-block;
  width: 0; 
  height: 0;
  transition: all $marker-duration;
  position: absolute;  
}

.button-wrap:focus:after {
  @include focusSettings(left);
}

.button-wrap:focus:before {  
  @include focusSettings(right);
}

Any hints and tipps concerning possible improvements highly welcomed. Especially the design and usability.

\$\endgroup\$
  • \$\begingroup\$ Judging from your code, the animation should run for all of the input boxes, but that is not happening in the snippet. Do you know the cause of this? \$\endgroup\$ – SirPython Jul 15 '16 at 13:45
  • \$\begingroup\$ @SirPython I've got only Internet Explorer on my workplace. So therefore no opportunity to test it with other browser. Here at home and now with Firefox I must say: You are right. :( \$\endgroup\$ – michael.zech Jul 15 '16 at 15:35
  • \$\begingroup\$ @SirPython Tried it again in a VM with Internet Explorer 11. There it all works and looks more intact. For to freak out. Anyway: Thanks for hints. I really appreciate it. \$\endgroup\$ – michael.zech Jul 15 '16 at 15:56
1
\$\begingroup\$

Bad UX

I don't have much to say about the code, but I want to comment on the UX of your form. Whenever the animation is running, the user is not allowed to enter anything into the input boxes. This is very poor UX as it forces the user to wait before filling out the next box when completing the form.

Animations can be cool, but if they become detrimental to UX, then it'd be best to find a middle ground.

In this case, I'd suggest somehow fixing your animation so that the user is still able to edit the input boxes when the animation is in progress.


Repeating animations

If the user clicks on a box and the animation starts, but the user clicks to another box before the animation finishes, the animation will repeat in the original box and focus will be reset to that box.

As said above, this is also seriously harming the user in the speed that they can fill out the form. If the user is too quick by less than a second, they could end up writing over older answers to the form that they wrote.

You can kind of fix this by deploying a setTimeout when the focus listener is called, and then destroying it if the listener is called again.

(function() {
  var inputs = document.querySelectorAll('input[type=text]');
  var userTriggered = true; // Avoiding recursion.
  var anim;

  inputs = Array.prototype.slice.call(inputs);

  inputs[0].focus();

  inputs.forEach(function(item) {
    if(anim) clearTimeout(anim);
    anim = setTimeout(function() {

        ... normal listener code...

    }, 1);
    });  
  });
})();

However, focus is still reset back to the old box with this code.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.