Adding Glossary Tooltips to Redactor Fields Using Craft CMS and Tippy.js
I'm working on an large new section to an existing client site and one of the requirements is to have a glossary that the various terms can be linked to across that section and then appear as tool tips.
Since I prefer to avoid plugins where possible when building websites, I set this up with a little javascript. It ended up being simpler than I expected.
This is how I did it.
Requirements
We are using Tippy.js for the tooltips and a redactor plugin to allow adding a class to links: Redactor Link Styles. This is needed so we can add a class of tooltip
to the link and turn it into a tooltip.
Create a channel called glossary and add fields to display the content you need. For my purposes I have two rich text fields. The first one Term is a redactor field that only allows for italics. The second redactor filed has standard rich text options.
Then create a template that does not extend your layout. and add code to display the fields. This template will be fetched with javascript and displayed in the tooltip. My template is below.
{# tooltip content #}
<span
class="inline-block p-4 bg-ivoryBrand" >
<p class="font-bold text-18 -mb-1">
{{ entry.term|striptags('<em>')|raw }}
</p>
<div class="prose">
{{ entry.definition|raw }}
</div><!-- /.prose -->
</span>
Javascript
Add Tippy.js to your project following the documentation. Then add the following javascript which first finds all elements with a class name of .tooltip
, then loops through each instance first adding a click event handler to prevent clicks working. This is necessary since the only way to create the tooltip and link to the glossary channel is using a link from within redactor.
// iterate over all .tooltip links
for(i = 0; i < tooltips.length; i++ ){
// prevent default
tooltips[i].addEventListener("click", function(e) {
e.preventDefault();
});
// more code coming
};
If there are a lot of tooltips on a page and and the fetch code runs on page load this will create a lot of server overhead and slow down page load. To prevent this we run fetch inside an event handler, onmouseenter
.
This forces the fetch to only happen when a visitor mouses over the link with the tooltip. You can confirm this is working by going to the xhr tab of dev tools and watching requests as you hover over a tooltip.
// on mouseenter fetch tooltip content and display it
tooltips[i].addEventListener("mouseenter", function(e) {
fetch(tipUrl)
.then(
function(response) {
if (response.status !== 200) {
console.log('there is a fetch problem. Status Code: ' + response.status);
return;
}
// lets look at the data returned
response.text().then(function(data) {
// set tipContent to the response data
tipContent= data;
// activate tippy.js with content from fetch
let instance = tippy(tip, {
content:tipContent,
allowHTML: true,
arrow:false,
theme: 'light',
// trigger: 'click',
hideonClick: false,
});
// call tippy here this way it only loads on mouseenter
instance.show();
})
}
)
});
And you can see the working test version here. Notice the xhr request doesn't come in until you hover over the link.
Conclusion
If you need a way for content editors to add glossary items that appear as tooltips in a redactor field this is a good way to do it. Next up, a page that displays all glossary items organized and filterable by alphabet.