IAN WALDRON IAN WALDRON

Simple Callout Boxes For Info, TLDR, And So On

Instructions and discussion on building simple, styled callout boxes to add context to article content and containing javascript functionality to add icons to the start of the element.
June 20, 2024

Here's an example tl;dr callout box.

Background

I had a need for simple callout boxes for items like tl;drs, info boxes, etc., like the one you see above. I'm using a WYSIWYG editor that I structured into my admin backend views to work on my articles and I don't want to spend a lot of time editing html in the editor. Instead, the solution I came up with was to have designated classes to style the callouts along with a bit of javascript to add icons and labels depending on the class.

For brevity, I'm only demonstrating the tl;dr & info options, but there's a whole assortment you could add.

CSS

For the style, my goal was to be consistent with the color schemes that Bootstrap has already established. We're used to seeing those colors around the web so there's a bit of intrinsic context there. The tl;dr theme is not a Bootstrap color, however. Because it doesn't really fit with the info/success/warning/danger set, I went with a purple to remain distinctly removed from their domain. For the background colors, I simply blended white into the RGB codes three times to lighten (add 255 to each color code and divide by two).

p, ul {
  padding: 15px;
  border: 1px solid;
  border-radius: 5px;
}

p.tldr, ul.tldr {
  border-color: rgb(128, 0, 128);
  background-color: rgb(240, 224, 240);
}

p.info {
  border-color: rgb(13, 202, 240);
  background-color: rgb(225, 249, 254);
}

ul li {
  margin-left: 20px; 
}

ul li:first-of-type {
  margin-top: 10px;
}

.tldr .icon, .info .icon {
  margin-right: 5px;
  font-weight: bolder;
}

.tldr .icon {
   color: rgb(128, 0, 128);
}

.info .icon {
   color: rgb(12, 182, 216);
}

.tldr .icon > i, .info .icon > i {
  margin-right: 5px;
}

JavaScript

To add another dimension of context, I use javascript to create a new element containing a Font Awesome icon and text label appropriate to the context. Because Font Awesome is moving towards a metered billing strategy requiring private "kits," I instead used their older Font Awesome 4 library to avoid this constraint so I don't have to expose a resource unique to my account in this example. If you're building this into your own project, you may want to create an account and use a private kit. There are free options available.

The flow of the JavaScript logic is as follows:

  • Select the elements based on certain classes
  • Loop through each element queried
  • Generate a new element and give it a class of 'icon'
  • Add the appropriate innerHTML containing the icon and label; and
  • Prepend (add to beginning of parent) the child to the contents of the parent
// add icon and label to parent

const tldrContent = '<i class="fa fa-bolt"></i>tldr:'
const infoContent = '<i class="fa fa-info-circle"></i>info:'

const targets = document.querySelectorAll('.tldr, .info')

targets.forEach(parent => {
  const child = document.createElement('span')
  child.classList.add('icon')
  if (parent.classList.contains('tldr')) {
    child.innerHTML = tldrContent
    parent.prepend(child)
  } else if (parent.classList.contains('info')) {
    child.innerHTML = infoContent
    parent.prepend(child)
  }
})

Result

Here's a Codepen to illustrate how everything comes together:

See the Pen callout-box by Ian Waldron (@Ian-Waldron) on CodePen.

Final Thoughts

If I were to continue adding functionality to this feature, I might check whether the contents of the parent element (<p> tag etc.), contain already something like a label. For example, the paragraph already begins with "tl;dr:" before the JavaScript runs. Since redundantly displaying this information could look a bit odd, you could check if the text contents begins with your labels and cut that text out if so. Since you might be affecting sentence structure, I would also check ensure there isn't any unexpected, residual punctuation before the content begins and that the first letter is capitalized.

That said, since I'm the only one working with content on my site, I'll just assume that I'm aware not to add any labels to the text contents directly and instead relying on the JavaScript to do so.

Here are the GitHub and Codepen links.