DEV Community

Cover image for Using Input Element as Display
Kristen Kinnear-Ohlmann
Kristen Kinnear-Ohlmann

Posted on • Originally published at kristenkinnearohlmann.dev

Using Input Element as Display

This week I picked a project back up that I set aside - the visual ITU alphabet for ham radio operators. Hams may need to spell out words and the ITU alphabet defines a regular English "code" word for each letter to ensure the letter is understood over the air very clearly. I had had a difficult time in the past memorizing the proper words. I know that tying a visual to a concept can assist with memory, so I created Visual ITU Alphabet.

I was returning back through projects to add box-sizing to manage how the content fit on the page, and I recalled that I had to not yet resolved the slight shift when the display letter was clicked and changed to an input. I wanted to make the transition as smooth as possible between the display state and the input state.

The original layout of the page contained a block element to display the current letter, and a hidden input that was invoked when the block element was clicked:

<div id="display-frame">
  <div id="display-letter" style="background-color: blue"></div>
  <div class="hidden change-letter" id="change-letter">
    <input
      class="change-letter"
      id="change-letter-input"
      type="text"
      maxlength="1"
      pattern="[A-Za-z]{1}"
    />
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

At some point after I released Visual ITU Alphabet, I created Minutes Only Timer for my husband. For that project, I resolved the issues of having an input that accepted numbers for time by using an input element for both the display and the input. I realized I could take this same approach with Visual ITU Alphabet.

The simplest step was to remove the former display block and retain only the input; I revised the block elements and classes to handle the styling for alignment and font:

<div class="display-frame">
  <div class="letter-entry">
    <input
      class="letter-input"
      id="letter-input-entry"
      type="text"
      maxlength="1"
      pattern="[A-Za-z]{1}"
    />
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

I styled the classes to ensure the input element, whether in "display mode" or "entry mode", would have a font and size that correlated to the other elements on the page, as well as maintain a consistent margin between the input and the letter image:

.display-frame {
  display: flex;
  flex-flow: column nowrap;
  margin: 2%;
  width: 75%;
}

.letter-entry {
  align-content: center;
  display: flex;
  justify-content: center;
  margin-bottom: 10px;
  padding-bottom: 10px;
}

.letter-input {
  border: none;
  font-family: "Times New Roman", Times, serif;
  font-size: 5rem;
  text-align: center;
  width: 200px;
}
Enter fullscreen mode Exit fullscreen mode

These changes allowed me to simplify the logic that handled the letter processing itself, as well as ensure the focus is removed from the input so the "display mode" looks like normal text:

const displayAlpha = () => {
  currentLetter = new AlphaLetter(alpha[alphaPosition])

  // after retrieving the letter value, invoke the blur() function to deselect the input
  letterInputEntry.value = currentLetter.letter
  letterInputEntry.blur()
  displayLetterImg.innerHTML = currentLetter.renderLetterImg()

  phoneticWord.textContent = currentLetter.phoneticWord
  pronunciation.innerHTML = currentLetter.stressPronounce()
}

const updateDisplayLetter = event => {
  const newLetter = event.target.value.toUpperCase()
  const newLetterPosition = alpha
    .map(element => element.letter)
    .indexOf(newLetter)
  alphaPosition = newLetterPosition

  displayAlpha()
}

// clear the value from the input
letterInputEntry.addEventListener("click", event => {
  letterInputEntry.value = ""
})

// update the letter if one was entered and the user clicked out of the field
letterInputEntry.addEventListener("blur", event => {
  if (letterInputEntry.value.length === 0) {
    letterInputEntry.value = currentLetter.letter
  }
  updateDisplayLetter(event)
})

// update the letter if one was entered and the user pressed enter
letterInputEntry.addEventListener("keyup", event => {
  const keyPressed = event.key

  if (keyPressed === "Enter") {
    if (letterInputEntry.value.length === 0) {
      letterInputEntry.value = currentLetter.letter
    }
    updateDisplayLetter(event)
  }
})
Enter fullscreen mode Exit fullscreen mode

It's quite delightful to be able to view the site on my mobile phone. Clicking and changing the letter no longer shifts content on the page, and the current letter is restored if a user clears the input, fails to put in a new letter and exits the input. While there are still other opportunities for refactoring this code, this functionality enhancement makes the app even easier to use while I review other changes.

Discussion (0)