javascriptcssmobileprogressive-web-appstext-cursor

show caret on readonly html input


I am creating a calculator, that I want to use on browser and mobile as progressive web app. I created my own input buttons and don't want to see the virtual keyboard on mobile. For that reason I am using the attribute readonly on the input.

I want to show the cursor, so the user knows, where the number or operator will be inserted.

Unfortunately a readonly input shows the cursor only in firefox mobile, not in chrome mobile. So I cannot rely on the built in cursor.

I need a way to show the cursor for the input field, while the virtual keyboard is not opened, when clicking into the input field.


Solution

  • To solve the issue, I implemented my own caret. I created a div with 1px width and proper height. The #caret is positioned relatively to the .input-group.

    To make it easy, I use a monospaced font on the input. So every character has same width. Then I just listen for any event on the input and update the position of the caret accordingly. text-shadow and transparent color make the original caret invisible on firefox mobile.

    My input field is aligned to the right.

    Updated https://jsfiddle.net/9fr46y2w/3/

    HTML

    <div class="input-group">
      <input type="text" id="input" onclick="showCaret(this);">
      <div id="caret"></div>
    </div>
    

    CSS

    #input {
      color: transparent;
      font-family: monospace;
      font-size: 36px;
      height: 48px;
      margin: 0;
      padding: 0;
      text-align: right;
      text-shadow: 0 0 0 #yourTextColor;
      width: 100%;
    }
    
    .input-group {
      margin: 0;
      padding: 0;
      position: relative;
    }
    
    #caret {
      background: white;
      color: transparent;
      height: 41px;
      position: absolute;
      top: 4px;
      right:0;
      width: 1px;
    
      animation-duration: 1s;
      animation-name: blink;
      animation-iteration-count: infinite;
    }
    
    @keyframes blink {
      from {
        opacity: 1; 
      }
    
      49.9% {
          opacity: 1;
      }
      50% {
        opacity: 0;
      }
    
      99.9% {
          opacity: 0;
      }
    
      to {
        opacity: 1;
      }
     } 
    

    JavaScript

    function showCaret(input) {
      let widthSizeRatio = 21.6/36;
      let charWidth = widthSizeRatio * 36;
      let length = input.value.length;
      let cur = input.selectionStart;
    
      document.getElementById("caret").style.right = Math.floor((length - cur) * charWidth) + "px";
    }