Add Inline “?” Tooltips

Add Inline “?” Tooltips
Small info icons next to key labels (“Win Rate,” “Increase in Estimates,” etc.) could explain terms in pop-ups without adding clutter. Helps keep a clean webpage, clean. :slightly_smiling_face:

Love the calculator, BTW!

2 Likes

Hi there and welcome to the Community, @Scott7 :waving_hand:

Thanks a lot for the feedback!

This is a really nice idea. We’ll try to consider it in the future, especially if more users upvote it.

As for now, our devs can create a custom code for adding tooltips. Could you just specify all labels, where you’d like to add it, and a screenshot of the tooltip placement?

1 Like

Wow, Max!

Thanks for the quick reply and offer to write custom code. I wasn’t expecting that!

Attached, is a screenshot of the calculator I made and one with what I envisioned for the tooltips. There are two versions of what the tooltip pop-up might look like in the example. One is basic gray for the icon pop-up and text. The other is a color that matches the theme of the calculator I built.

The tooltip would replace optional Hint text for all items in the Fields column.

Note: When I built this calculator the Fields column was shorter than the Calculations column, which gave the Calculator an unbalanced look. To fix that I added extra blank lines in the Hint text to space the Fields out, making that column the same height as the Equations column.

If the tooltip pop-ups are added permanently, perhaps a control to make the height of both columns match could be added. I know, I’m getting greedy here with your offer to help with the tool tips. I just wanted to point that out.

Thanks again for the speedy reply, Max.

2 Likes

Thanks a lot for clarification!

The final question: would you like to add tooltips only to the calculator fields or to the Results section as well?

1 Like

Just to the Calculator fields. The Results section looks good as is, to me.

Thanks, again!

Scott Lindy

Lindy Media AI Consultinghttps://www.lindymedia.net/

404-983-2827

2 Likes

Thank you!

I’ve forwarded your request to the devs and will update you once the solution is ready :wink:

1 Like

Hi there, @Scott7 :waving_hand:

Thank you for waiting!

We’ve added this code to the Custom CSS field on the Settings tab of your widget’s settings:

.es-hint-icon {
  position: absolute;
  top: 32%;
  left: 96%;
  transform: translateY(-39%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  cursor: default;
  color: #e53935;
  z-index: 900;
  outline: none;
}

@media (max-width: 680px) {
  .es-hint-icon {
    margin-left: 10px;
  }
}

.es-hint-icon svg {
  width: 20px;
  height: 20px;
  display: block;
  fill: red;
}

.es-hint-tooltip {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%) translateY(6px);
  white-space: nowrap;
  padding: 6px 8px;
  border-radius: 6px;
  font-size: 12px;
  line-height: 1;
  background: rgb(255 44 44 / 85%);
  color: rgb(255 255 255);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.2);
  opacity: 0;
  pointer-events: none;
  transition: opacity .12s ease, transform .12s ease;
  z-index: 1000;
}

.es-hint-tooltip::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 6px solid transparent;
  border-top-color: rgb(255 44 44 / 85%);
}

.es-hint-icon.show .es-hint-tooltip,
.es-hint-icon:focus-within .es-hint-tooltip,
.es-hint-icon:hover .es-hint-tooltip {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
  pointer-events: auto;
}

.es-hint-label-posfix {
  position: relative !important;
}

.es-field-layout-hint {
  display: none;
}

And this script was added to the Custom JS field on the Settings tab:

const svgIcon = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000" height="30px" width="30px" version="1.1" id="Capa_1" viewBox="0 0 27.963 27.963" xml:space="preserve">
<g>
	<g id="c129_exclamation">
		<path d="M13.983,0C6.261,0,0.001,6.259,0.001,13.979c0,7.724,6.26,13.984,13.982,13.984s13.98-6.261,13.98-13.984    C27.963,6.259,21.705,0,13.983,0z M13.983,26.531c-6.933,0-12.55-5.62-12.55-12.553c0-6.93,5.617-12.548,12.55-12.548    c6.931,0,12.549,5.618,12.549,12.548C26.531,20.911,20.913,26.531,13.983,26.531z"/>
		<polygon points="15.579,17.158 16.191,4.579 11.804,4.579 12.414,17.158   "/>
		<path d="M13.998,18.546c-1.471,0-2.5,1.029-2.5,2.526c0,1.443,0.999,2.528,2.444,2.528h0.056c1.499,0,2.469-1.085,2.469-2.528    C16.441,19.575,15.468,18.546,13.998,18.546z"/>
	</g>
	<g id="Capa_1_207_">
	</g>
</g>
</svg>`;

const waitForElement = (selector, root = document) => new Promise(res => {
  const observer = new MutationObserver(() => {
    const element = root.querySelector(selector);
    if (element) {
      res(element);
      observer.disconnect();
    }
  });

  observer.observe(root, {
    childList: true,
    subtree: true
  });
});

function processField(field) {
  if (!field || field._hintProcessed) return;
  const hintContainer = field.querySelector('.es-field-layout-hint') || field.querySelector('.es-field-hint');
  if (!hintContainer) return;
  const hintTextEl = hintContainer.querySelector('div') || hintContainer;
  const hintText = (hintTextEl && hintTextEl.textContent || '').trim();
  if (!hintText) return;

  const label = field.querySelector('label');
  if (!label) return;
  if (label.querySelector('.es-hint-icon')) return; // уже есть

  if (getComputedStyle(label).position === 'static') {
    label.classList.add('es-hint-label-posfix');
  }

  const icon = document.createElement('div');
  icon.type = 'button';
  icon.className = 'es-hint-icon';
  icon.setAttribute('aria-haspopup', 'true');
  icon.setAttribute('aria-expanded', 'false');
  icon.setAttribute('tabindex', '0');
  icon.innerHTML = svgIcon;

  const tooltip = document.createElement('div');
  tooltip.className = 'es-hint-tooltip';
  const tooltipId = `es-hint-tooltip-${Date.now()}`;
  tooltip.id = tooltipId;
  tooltip.textContent = hintText;
  icon.appendChild(tooltip);
  icon.setAttribute('aria-describedby', tooltipId);

  icon.addEventListener('mouseenter', () => {
    icon.classList.add('show');
    icon.setAttribute('aria-expanded', 'true');
  });
  icon.addEventListener('mouseleave', () => {
    icon.classList.remove('show');
    icon.setAttribute('aria-expanded', 'false');
  });
  icon.addEventListener('focus', () => {
    icon.classList.add('show');
    icon.setAttribute('aria-expanded', 'true');
  });
  icon.addEventListener('blur', () => {
    icon.classList.remove('show');
    icon.setAttribute('aria-expanded', 'false');
  });
  icon.addEventListener('click', (e) => {
    e.stopPropagation();
    icon.classList.toggle('show');
    icon.setAttribute('aria-expanded', icon.classList.contains('show') ? 'true' : 'false');
  });

  document.addEventListener('click', (e) => {
    if (!icon.contains(e.target)) {
      icon.classList.remove('show');
      icon.setAttribute('aria-expanded', 'false');
    }
  }, {
    capture: true
  });

  label.appendChild(icon);

  field._hintProcessed = true;
}



waitForElement('.es-field-layout-element').then(() => {
  const fieldsWithHint = document.querySelectorAll('.es-field-layout-element:has(.es-field-layout-hint)');
  fieldsWithHint.forEach(field => {
    processField(field);
  });


});

Note: Since Custom JS codes don’t operate in the preview mode, you’ll see the final result on your website (not in the widget editor)


Please check your website and let me know if you like the custom tooltips :slightly_smiling_face:

1 Like

It looks great, Max! Thank you so much!

Scott Lindy

2 Likes