---
title: Adding Glossary Tooltips to Redactor Fields Using Craft CMS and Tippy.js
date: 2022-02-02T09:47:00-05:00
author: cc_admin
canonical_url: "https://caffeinecreations.ca/blog/adding-glossary-tooltips-to-redactor-fields-using-craft-cms-and-tippy-js/"
section: Blog
---
![Tooltips](https://caffeinecreations.ca/uploads/blog/_1920x660_crop_center-center_none_ns/tooltips.jpg)

- [Code](https://caffeinecreations.ca/blog/category/code/), [Tutorial](https://caffeinecreations.ca/blog/category/code/tutorial/), [CraftCMS](https://caffeinecreations.ca/blog/category/craftcms/), [Craft Tips](https://caffeinecreations.ca/blog/category/craftcms/craft-tips/)

# 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](https://caffeinecreations.ca/blog/the-dangers-of-over-reliance-on-plugins-in-website-builds/) 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](https://atomiks.github.io/tippyjs/) for the tooltips and a redactor plugin to allow adding a class to links: [Redactor Link Styles](https://github.com/simplicate-web/redactor-link-class). 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.

```
<button class="absolute z-10 flex items-center justify-center w-8 h-8 -translate-y-1/2  -right-4 -top-4" clipboard="" title="Copy to Clipboard" to="" type="button" x-clipboard.raw="{# 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>" x-data="">
	<svg class="h-5 w-5" viewbox="0 0 64 64" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
  <rect fill="#f3f4f6" height="53" rx="3" width="41" x="7" y="2"></rect>
  <rect fill="#f3f4f6" height="51" rx="3" width="39" x="19" y="11"></rect>
  <path d="M53.98 9.143h-3.97c-.082 0-.155.028-.232.047V5.023C49.778 2.253 47.473 0 44.64 0H10.217C7.384 0 5.08 2.253 5.08 5.023v46.843c0 2.77 2.305 5.023 5.138 5.023h6.037v2.268c0 2.67 2.216 4.843 4.941 4.843H53.98c2.725 0 4.942-2.173 4.942-4.843v-45.17c0-2.671-2.217-4.844-4.942-4.844zM7.11 51.866V5.023c0-1.649 1.394-2.991 3.106-2.991H44.64c1.712 0 3.106 1.342 3.106 2.99v46.844c0 1.649-1.394 2.991-3.106 2.991H10.217c-1.712 0-3.106-1.342-3.106-2.99zm49.778 7.29c0 1.551-1.306 2.812-2.91 2.812H21.195c-1.604 0-2.91-1.26-2.91-2.811v-2.268H44.64c2.833 0 5.138-2.253 5.138-5.023V11.128c.077.018.15.047.233.047h3.968c1.604 0 2.91 1.26 2.91 2.811v45.17z"></path>
  <path d="M38.603 13.206H16.254a1.015 1.015 0 1 0 0 2.032h22.35a1.015 1.015 0 1 0 0-2.032zM38.603 21.333H16.254a1.015 1.015 0 1 0 0 2.032h22.35a1.015 1.015 0 1 0 0-2.032zM38.603 29.46H16.254a1.015 1.015 0 1 0 0 2.032h22.35a1.015 1.015 0 1 0 0-2.032zM28.444 37.587h-12.19a1.015 1.015 0 1 0 0 2.032h12.19a1.015 1.015 0 1 0 0-2.032z"></path>
</svg>
<div class="sr-only">Copy to clipboard</div></button>```twig
{# 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](https://atomiks.github.io/tippyjs/) 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.

```
<button class="absolute z-10 flex items-center justify-center w-8 h-8 -translate-y-1/2  -right-4 -top-4" clipboard="" title="Copy to Clipboard" to="" type="button" x-clipboard.raw="// 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
  };" x-data="">
	<svg class="h-5 w-5" viewbox="0 0 64 64" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
  <rect fill="#f3f4f6" height="53" rx="3" width="41" x="7" y="2"></rect>
  <rect fill="#f3f4f6" height="51" rx="3" width="39" x="19" y="11"></rect>
  <path d="M53.98 9.143h-3.97c-.082 0-.155.028-.232.047V5.023C49.778 2.253 47.473 0 44.64 0H10.217C7.384 0 5.08 2.253 5.08 5.023v46.843c0 2.77 2.305 5.023 5.138 5.023h6.037v2.268c0 2.67 2.216 4.843 4.941 4.843H53.98c2.725 0 4.942-2.173 4.942-4.843v-45.17c0-2.671-2.217-4.844-4.942-4.844zM7.11 51.866V5.023c0-1.649 1.394-2.991 3.106-2.991H44.64c1.712 0 3.106 1.342 3.106 2.99v46.844c0 1.649-1.394 2.991-3.106 2.991H10.217c-1.712 0-3.106-1.342-3.106-2.99zm49.778 7.29c0 1.551-1.306 2.812-2.91 2.812H21.195c-1.604 0-2.91-1.26-2.91-2.811v-2.268H44.64c2.833 0 5.138-2.253 5.138-5.023V11.128c.077.018.15.047.233.047h3.968c1.604 0 2.91 1.26 2.91 2.811v45.17z"></path>
  <path d="M38.603 13.206H16.254a1.015 1.015 0 1 0 0 2.032h22.35a1.015 1.015 0 1 0 0-2.032zM38.603 21.333H16.254a1.015 1.015 0 1 0 0 2.032h22.35a1.015 1.015 0 1 0 0-2.032zM38.603 29.46H16.254a1.015 1.015 0 1 0 0 2.032h22.35a1.015 1.015 0 1 0 0-2.032zM28.444 37.587h-12.19a1.015 1.015 0 1 0 0 2.032h12.19a1.015 1.015 0 1 0 0-2.032z"></path>
</svg>
<div class="sr-only">Copy to clipboard</div></button>```javascript
// 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.

```
<button class="absolute z-10 flex items-center justify-center w-8 h-8 -translate-y-1/2  -right-4 -top-4" clipboard="" title="Copy to Clipboard" to="" type="button" x-clipboard.raw="// 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();
        })
      }
    )
});" x-data="">
	<svg class="h-5 w-5" viewbox="0 0 64 64" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
  <rect fill="#f3f4f6" height="53" rx="3" width="41" x="7" y="2"></rect>
  <rect fill="#f3f4f6" height="51" rx="3" width="39" x="19" y="11"></rect>
  <path d="M53.98 9.143h-3.97c-.082 0-.155.028-.232.047V5.023C49.778 2.253 47.473 0 44.64 0H10.217C7.384 0 5.08 2.253 5.08 5.023v46.843c0 2.77 2.305 5.023 5.138 5.023h6.037v2.268c0 2.67 2.216 4.843 4.941 4.843H53.98c2.725 0 4.942-2.173 4.942-4.843v-45.17c0-2.671-2.217-4.844-4.942-4.844zM7.11 51.866V5.023c0-1.649 1.394-2.991 3.106-2.991H44.64c1.712 0 3.106 1.342 3.106 2.99v46.844c0 1.649-1.394 2.991-3.106 2.991H10.217c-1.712 0-3.106-1.342-3.106-2.99zm49.778 7.29c0 1.551-1.306 2.812-2.91 2.812H21.195c-1.604 0-2.91-1.26-2.91-2.811v-2.268H44.64c2.833 0 5.138-2.253 5.138-5.023V11.128c.077.018.15.047.233.047h3.968c1.604 0 2.91 1.26 2.91 2.811v45.17z"></path>
  <path d="M38.603 13.206H16.254a1.015 1.015 0 1 0 0 2.032h22.35a1.015 1.015 0 1 0 0-2.032zM38.603 21.333H16.254a1.015 1.015 0 1 0 0 2.032h22.35a1.015 1.015 0 1 0 0-2.032zM38.603 29.46H16.254a1.015 1.015 0 1 0 0 2.032h22.35a1.015 1.015 0 1 0 0-2.032zM28.444 37.587h-12.19a1.015 1.015 0 1 0 0 2.032h12.19a1.015 1.015 0 1 0 0-2.032z"></path>
</svg>
<div class="sr-only">Copy to clipboard</div></button>```javascript
// 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.

![](https://caffeinecreations.ca/uploads/blog/tooltip.gif)

#### 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.

## Related Articles

[![Add a Modal from a Redactor Field in Craft CMS Thumbnail](https://caffeinecreations.ca/uploads/blog/_680x320_crop_center-center_65_none_ns/craftcms.jpg)### Add a Modal from a Redactor Field in Craft CMS](https://caffeinecreations.ca/blog/add-a-modal-from-a-redactor-field-in-craft-cms/)

[![Reactive Pagination With Sprig and Craft Thumbnail](https://caffeinecreations.ca/uploads/blog/_680x320_crop_center-center_65_none_ns/sprig-hero.jpg)### Reactive Pagination With Sprig and Craft](https://caffeinecreations.ca/blog/reactive-pagination-with-sprig-and-craft/)

[![Grouping Entries by First Letter of Last Name Thumbnail](https://caffeinecreations.ca/uploads/blog/_680x320_crop_center-center_65_none_ns/alphabet.jpg)### Grouping Entries by First Letter of Last Name](https://caffeinecreations.ca/blog/grouping-entries-by-first-letter-of-last-name/)
