home ~ projects ~ socials

Check If Content In An Element Is Wrapping

Introduction

I designed code blocks for my site to include copy buttons, font sizing controls and wrapping toggles1. The wrapping toggles only show up if the text needs to wrap. This is how I'm doing that check.

Basic Setup

Let's start creating two example divs that are bound to a width of 200px and a button we can press to check for wrapping.

Alfa bravo

Wraps:

Alfa bravo charlie delta echo foxtrot golf hotel india

Wraps:

The JavaScript

Here's the full script that powers the check when you press the button. It makes a new element with the same styles and innerHTML as the element being checked then swithes its .style.whiteSpace to nowrap which prevents text from wrapping like it normally would. With that wrapping off we compare the .scrollWidth of the new element and the .offsetWidth of the source. If the .scorllWidth is bigger it means there's wrapping.

JavaScript

function checkForWraps() {
  const items = document.querySelectorAll(".bounded")
  items.forEach((item) => {
    if (isElementWrapping(item)) {
      item.querySelector(".report").innerHTML = "YES"
      item.style.border = "1px solid red"
    } else {
      item.querySelector(".report").innerHTML = "NO"
      item.style.border= "1px solid green"
    }
  })
}

function isElementWrapping(el) {
  const compareEl = document.createElement(el.localName)
  compareEl.style.visibility = 'hidden'
  const styles = window.getComputedStyle(el);
  if (styles.cssText !== '') {
      compareEl.style.cssText = styles.cssText;
  } else {
      const cssText = Object.values(styles).reduce(
          (css, propertyName) => 
              `${css}${propertyName}:${styles.getPropertyValue(
                  propertyName
              )};`
      );
      compareEl.style.cssText = cssText
  }
  compareEl.innerHTML = el.innerHTML
  compareEl.style.position = 'absolute'
  compareEl.style.top = 0
  compareEl.style.left = 0
  compareEl.style.whiteSpace = 'nowrap'
  document.body.appendChild(compareEl)
  const isWrapping = 
    compareEl.scrollWidth > el.offsetWidth ? true : false
  compareEl.remove()
  return isWrapping 
}

document.addEventListener('DOMContentLoaded', () => {
  const checkButton = document.querySelector('.checkButton')
  checkButton.addEventListener('click', checkForWraps)
})

More Details

  • isElementWrapping(el) is a stand-alone function that can be used on its own. It returns true if it detects wrapping and false if it doesn't.
  • I'm not using .cloneNode() since it can produce dupliate IDs.
  • This method makes an attempt to keep the same styles via .getComputedStyle() but there are probably cases where this isn't exact (e.g. if there's a style applied in an inner elemnet that is effected by something above the original element.) You'll want to check againg each specific thing that you're working with to make sure things are doing what you expect.
  • The comparison node is hidden from view during the measurment and then removed from the DOM after confiming if there's a wrap or not.
-- end of line --

References

Footnotes