Search code examples
javascripthtmlcssinputstyling

Split input into separate boxes


I am looking to separate an input into individual character/digit boxes, like this photo

Ideally, entering a digit would take you to the next input box and each one would be highlighted separately with the active border. I can use a combination of styling and Javascript to accomplish this.

Any insight would be really helpful! Thanks in advance.


Solution

  • Here's one way to implement this pattern:

    HTML:

    <div class="digits">
      <input type="text" maxlength="1" name="digit1" />
      <input type="text" maxlength="1" name="digit2" />
      <input type="text" maxlength="1" name="digit3" />
      <input type="text" maxlength="1" name="digit4" />  
    </div>
    

    CSS:

    input {
      font-size: 2rem;
      width: 1.5rem;
      text-align: center;
    }
    input:focus {
      border: 2px solid yellowgreen;
      outline: none;
    }
    

    JAVASCRIPT:

    // Listen on the 'input' event inside the .digits area:
    document.querySelector(".digits").addEventListener("input", function(e){
    
      // Exclude non-numeric characters from input:
      e.target.value = e.target.value.replace(/[^0-9]/g,'');
    
      // If the input value is filled and there is a neighbouring element that is input, then focus on that element:
      if ( e.target.value !== "" && e.target.nextElementSibling && e.target.nextElementSibling.nodeName === "INPUT" ){
    
        e.target.nextElementSibling.focus();
    
      }
    
    });
    

    2) In case you want the input values to be updated when already filled:

    <div class="digits">
      <input type="text" name="digit1" />
      <input type="text" name="digit2" />
      <input type="text" name="digit3" />
      <input type="text" name="digit4" />  
    </div>
    
    document.querySelector(".digits").addEventListener("input", function(e){
      e.target.value = e.data.replace(/[^0-9]/g,'');
      if ( e.target.value !== "" && e.target.nextElementSibling && e.target.nextElementSibling.nodeName === "INPUT" ){
        e.target.nextElementSibling.focus();
      } 
    });
    

    document.querySelector("input").focus();
    document.querySelector(".digits").addEventListener("input", function({ target, data }){
    
      // Exclude non-numeric characters (if a value has been entered)
      data && ( target.value = data.replace(/[^0-9]/g,'') );
      
      const hasValue = target.value !== "";
      const hasSibling = target.nextElementSibling;
      const hasSiblingInput = hasSibling && target.nextElementSibling.nodeName === "INPUT";
    
      if ( hasValue && hasSiblingInput ){
    
        target.nextElementSibling.focus();
      
      } 
    
    });
    input {
      font-size: 3rem;
      width: 2.6rem;
      border: 2px solid #aaa;
      text-align: center;
      box-shadow: 0 0 8px rgba(0,0,0,0.25);
    }
    input:focus {
      border: 2px solid yellowgreen;
      outline: none;
    }
    
    /* DECORATION */
    
    input:focus {
      animation-name: zoom;
      animation-duration: 200ms;
    }
    
    @keyframes zoom {
      from {
        
      }
      to {
        transform: scale(2);
      }
    }
    
    body {
      display: flex;
      align-items: center;
      justify-content: center;
      height: 100vh;
      background-color: lightgray;
    }
    
    .digits {
      padding: 20px;
      display: inline-block;
    }
    <div class="digits">
      <input type="text" name="digit1" />
      <input type="text" name="digit2" />
      <input type="text" name="digit3" />
      <input type="text" name="digit4" />  
      <input type="text" name="digit5" />  
    </div>

    Codepen (Contains some extra validation and effects)