Search code examples
javascripthtmlcssinputcontenteditable

How do you make the Highlighted Area for a ContentEditable box larger?


I'm building a UI that uses contentEditable elements to input data into a model.

At the moment, when you select the element, the box automatically highlights the box's current input only, see below:

enter image description here

This is an issue as it can sometimes hide the cursor. I would like to increase the default size of the highlighted box to something like 20px, however, adding a min-width style to each element doesn't seem to make a difference to the size of the highlighted box.

What styles do I have to set/ what do I have to change to make this highlighted box larger?

Please see a code snippet of my current solution below:

const update_display = (id) => {
    const value = document.querySelector(`#${id}_input`).value;
    document.querySelector(`#${id}_display`).innerText = value;
};

const displays = document.querySelectorAll("label a");

displays.forEach((display) => {
      display.style.marginRight = "5px";
      display.style.marginLeft = "5px";
    });
 
displays.forEach((display) => {
      display.addEventListener("keydown", (event) => {
        if (event.key === 'Enter') {
            event.preventDefault()
        }
      })
    });
<label class="form-label">E_1: <a id="E1_display" contenteditable="true">0.85</a></label>
<input
    id="E1_input"
    type="range"
    class="form-range"
    oninput="update_display('E1');run_surrogate()"
    min="0.7"
    max="1.0"
    step="0.01"
/>


Solution

  • <a> is an inline element, so properties such as width and height have no affect. While display: inline-block is a viable solution, display: inline-flex makes aligning content easier. In Figure I is a part of the HTML of the example based on your OP. Figure II is the CSS applied to the HTML of Figure I.

    Figure I

    <label class="form-label">E_1: 
      <a href="#" id="E1_display" name="display" class="form-display" contenteditable>0.85</a>
    </label>
    <!-- Range is wrapped in a <label> -->
    <label class="form-label">
      <input id="E1_range" name="range" class="form-range" min="0.7" max="1.0" step="0.01" value="0.85">
    </label>
    

    Figure II

    .form-display {
      /* inline-block + flex 
         Explicit width and height applies
         Able to set vertical and horizontal position on content
      */
      display: inline-flex; 
      /* Content is vertically centered */
      align-items: center;
      /* ch is the width of a zero: "0" */
      min-width: 3.5ch;
      height: 26px;
      /* rem is equal to the default font-size found on <html> */
      margin: 0 0.5rem;
      padding: 0 1ch;
      /* Needed because href="#" is added to each <a> - href allows <a>
         to be recognized and collected as a live HTMLCollection via 
         document.links
      */
      color: black;
      /* As previous comment */
      text-decoration: none;
    }
    
    .form-label {
      display: inline-flex;
      align-items: center;
      margin-bottom: 0.75rem
    }
    

    The rest of the changes are not required, they are optional but strongly recommended.

    const main = document.forms.main;
    const displays = Array.from(document.links);
    
    displays.forEach((display) => {
      display.addEventListener("keydown", function(event) {
        if (event.key === 'Enter') {
          event.preventDefault()
        }
      });
    });
    
    main.addEventListener("input", function(event) {
      const fc = this.elements;
      if (event.target !== this) {
        if (event.target.name === "range") {
          const id = event.target.id.slice(1, 2);
          const dis = document.getElementById("E" + id + "_display");
          dis.textContent = event.target.value;
        }
        if (event.target.name === "display") {
          const id = event.target.id.slice(1, 2);
          const rng = fc["E" + id + "_range"];
          rng.value = event.target.textContent;
        }
      }
    });
    html {
      font: 300 2ch/1.15 "Segoe UI";
    }
    
    #main {
      display: grid;
      grid-template-columns: 1fr 2fr;
      grid-template-rows: 1fr 1fr 1fr;
      grid-column-gap: 10px;
      grid-row-gap: 10px;
      justify-items: stretch;
      align-items: stretch
    }
    
    .form-display {
      display: inline-flex;
      align-items: center;
      min-width: 3.5ch;
      height: 26px;
      margin: 0 0.5rem;
      padding: 0 1ch;
      color: black;
      text-decoration: none;
    }
    
    .form-label {
      display: inline-flex;
      align-items: center;
      margin-bottom: 0.75rem
    }
    <form id="main">
      <label class="form-label">E_1: <a href="#" id="E1_display" name="display" class="form-display" contenteditable>0.85</a></label>
      <label class="form-label"><input id="E1_range" name="range" class="form-range" type="range" min="0.7" max="1.0" step="0.01" value="0.85" /></label>
    
      <label class="form-label">E_2: <a href="#" id="E2_display" name="display" class="form-display" contenteditable>0.95489</a></label>
      <label class="form-label"><input id="E2_range" name="range" class="form-range" type="range" min="0.7" max="1.0" step="0.01" value="0.95489" /></label>
    
      <label class="form-label">E_3: <a href="#" id="E3_display" name="display" class="form-display" contenteditable>0.8</a></label>
      <label class="form-label"><input id="E3_range" name="range" class="form-range" type="range" min="0.7" max="1.0" step="0.01" value="0.8" /></label>
    </form>