Tooltip

Tooltip displays additional information without interrupting user flow.

Usage

Tooltip

Bare Tooltip HTML:


                                                
                                                <div class="Tooltip" data-spirit-placement="top">
                                                  Hello there!
                                                  <span class="Tooltip__arrow"></span>
                                                </div>

Feature Flag: Data Selector Placement

Tooltip placement is currently using CSS modifiers. In the future it will be using data-spirit-placement attribute in order to make the placement independent of the component and compatible with Floating UI. To enable this behavior now you can use the feature flag, either set the $tooltip-enable-data-placement Sass feature flag to true or use the spirit-feature-tooltip-enable-data-placement CSS class on any parent of the Tooltip.

For more info, see main README.

⚠️ DEPRECATION NOTICE

CSS modifiers Tooltip--top, Tooltip--rightTop, Tooltip--bottom, etc. are deprecated and will be removed in the next major release. Use data-spirit-placement attribute instead.

Also both axis side placements are renamed from top-left, top-right, right-top, right-bottom, etc. to top-start, top-end, right-start, right-end, etc. Old names are deprecated and will be removed in the next major release.

What are deprecations?

Linking with Content

To display a Tooltip along your content, simply place it in the DOM next to it. Tooltip is positioned relative to the closest parent element with position: relative or position: absolute. You may either provide the CSS yourself or you can use the prepared TooltipWrapper component.

👉 Basic Tooltip is static and doesn't react on user interaction. Read further to see how to provide the desired behavior.

👉 You don't need TooltipWrapper when your Tooltip is already being positioned correctly.

👉 Depending on your layout, you may need to provide additional styling to shrink TooltipWrapper box model, e.g. using d-inline-block utility class. (This probably won't be necessary inside flexbox and grid layouts.)

👉 Link Tooltip to your content using id and aria-describedby attributes for improved accessibility.


                                                
                                                <div class="TooltipWrapper d-inline-block">
                                                  <a href="#" aria-describedby="my-tooltip">I have a tooltip!</a>
                                                  <div id="my-tooltip" class="Tooltip" data-spirit-placement="top">
                                                    Hello there!
                                                    <span class="Tooltip__arrow"></span>
                                                  </div>
                                                </div>

Placement

Tooltip implements the Placement Dictionary for placement. The dictionary values are used as a value of data attribute data-spirit-placement, e.g. data-spirit-placement="top", data-spirit-placement="right-end", etc.

For JS-controlled positioning please use the data-spirit-placement-controlled attribute instead of specifying the placement using the data-spirit-placement modifiers (more on that below).


                                                
                                                <div class="Tooltip" data-spirit-placement="right-start">
                                                  Tooltip on right
                                                  <span class="Tooltip__arrow"></span>
                                                </div>

Interaction

Pure CSS

To display Tooltip on hover and focus (for focusable elements, i.e. mainly links, buttons or inputs), add TooltipTarget class to your element and place Tooltip HTML right after it.


                                                
                                                <div class="TooltipWrapper d-inline-block">
                                                  <a href="#" class="TooltipTarget" aria-describedby="my-tooltip-on-hover">I have a tooltip!</a>
                                                  <div id="my-tooltip-on-hover" class="Tooltip" data-spirit-placement="top">
                                                    Hello there!
                                                    <span class="Tooltip__arrow"></span>
                                                  </div>
                                                </div>

👉 Elements that are not focusable will not trigger Tooltip for keyboard users. Add tabindex="0" to non-focusable elements to ensure keyboard accessibility.


                                                
                                                <div class="TooltipWrapper d-inline-block">
                                                  <span class="TooltipTarget" aria-describedby="my-tooltip-on-focus" tabindex="0">I have a tooltip!</span>
                                                  <div id="my-tooltip-on-focus" class="Tooltip" data-spirit-placement="top">
                                                    Hello there!
                                                    <span class="Tooltip__arrow"></span>
                                                  </div>
                                                </div>

Similar approach is also required for disabled elements. Disabled elements are not interactive which means users cannot hover, focus or click them to trigger a Tooltip. As a workaround, you'll want to trigger the Tooltip from a wrapper <div> or <span>, ideally made keyboard-focusable using tabindex="0".


                                                
                                                <div class="TooltipWrapper d-inline-block">
                                                  <div class="TooltipTarget" aria-describedby="my-tooltip-for-disabled-button" tabindex="0">
                                                    <button type="button" disabled>I have a tooltip though I'm disabled</button>
                                                  </div>
                                                  <div id="my-tooltip-for-disabled-button" class="Tooltip" data-spirit-placement="top">
                                                    Hello there!
                                                    <span class="Tooltip__arrow"></span>
                                                  </div>
                                                </div>

JavaScript

It's not always possible to apply custom CSS class on an element, e.g. when using a component that doesn't accept custom class names. Or maybe you even want to trigger Tooltip programmatically from outside the target element. For this kind of task Tooltip responds to interaction classes is-hidden and is-visible.


                                                
                                                <button type="button" id="tooltip-trigger" data-spirit-target="#my-js-controlled-tooltip">Toggle tooltip</button>
                                                <div class="TooltipWrapper d-inline-block">
                                                  <div aria-describedby="my-js-controlled-tooltip">I have an externally-triggered tooltip</div>
                                                  <div id="my-js-controlled-tooltip" class="Tooltip is-hidden" data-spirit-placement="top">
                                                    Hello there!
                                                    <span class="Tooltip__arrow"></span>
                                                  </div>
                                                </div>

                                                
                                                const toggleTooltip = (event) => {
                                                  const tooltipElement = document.querySelector(event.currentTarget.dataset.target);
                                                  tooltipElement.classList.toggle('is-hidden');
                                                  tooltipElement.classList.toggle('is-visible');
                                                };
                                                
                                                document.querySelector('#tooltip-trigger').addEventListener('click', toggleTooltip);

Dismissible Tooltip

Tooltip can be made dismissible by following these steps:

  1. Add Tooltip--dismissible modifier class on Tooltip.
  2. Add closing button with Tooltip__close class.
  3. Bind JS plugin using data-spirit-dismiss="tooltip" and data-spirit-target attributes on the closing button.

                                                
                                                <div id="my-dismissible-tooltip" class="Tooltip Tooltip--dismissible" data-spirit-placement="right">
                                                  Close me
                                                  <button
                                                    type="button"
                                                    class="Tooltip__close"
                                                    data-spirit-dismiss="tooltip"
                                                    data-spirit-target="#my-dismissible-tooltip"
                                                    aria-controls="my-dismissible-tooltip"
                                                    aria-expanded="true"
                                                  >
                                                    <svg width="24" height="24" aria-hidden="true">
                                                      <use xlink:href="/icons/svg/sprite.svg#close" />
                                                    </svg>
                                                    <span class="accessibility-hidden">Close</span>
                                                  </button>
                                                  <span class="Tooltip__arrow"></span>
                                                </div>

Advanced Positioning

While the basic setup can be sufficient in some scenarios, dropping a Tooltip usually won't be so easy. To handle all tricky situations and edge cases automatically, including smart position updates to ensure Tooltip visibility, we recommend involving an external library designed specifically for this purpose.

Placement

When controlling Tooltip position with JavaScript, use data-spirit-placement attribute instead of CSS modifiers (Tooltip--top etc.) to set Tooltip placement. All Placement Dictionary values are supported.


                                                
                                                <div id="my-advanced-tooltip" class="Tooltip" data-spirit-placement="top">
                                                  Hello there!
                                                  <span class="Tooltip__arrow"></span>
                                                </div>

If you have the Data Selector Placement feature flag enabled, set data-spirit-placement-controlled on the .Tooltip to control it and prevent conflicts with the default CSS positioning.


                                                
                                                <div id="my-advanced-tooltip" class="Tooltip" data-spirit-placement-controlled>
                                                  Hello there!
                                                  <span class="Tooltip__arrow"></span>
                                                </div>

Arrow

When controlling Tooltip arrow with JavaScript, set data-spirit-element="arrow" on the .Tooltip__arrow to control it and prevent conflicts with the default CSS positioning.


                                                
                                                <div id="my-advanced-tooltip" class="Tooltip" data-spirit-placement-controlled>
                                                  Hello there!
                                                  <span class="Tooltip__arrow" data-spirit-element="arrow"></span>
                                                </div>

Trigger

You can choose whether you want to open the tooltip on click and/or hover. By default, both options are active, e.g., data-spirit-trigger="click, hover". If you only want the click trigger, you need to specify the trigger, as shown in the example below. This setup might be preferable when you have a link in your tooltip, for example.


                                                
                                                <button type="button" id="tooltip-trigger" data-spirit-toggle="tooltip" data-spirit-target="#my-tooltip-trigger">
                                                  Toggle tooltip
                                                </button>
                                                <div class="TooltipWrapper d-inline-block">
                                                  <div
                                                    id="my-tooltip-trigger"
                                                    class="Tooltip is-hidden"
                                                    data-spirit-trigger="click"
                                                    <!--
                                                    Only
                                                    `click`
                                                    trigger
                                                    is
                                                    active
                                                    now.
                                                    --
                                                  >
                                                    > You can click on the link: <a href="#">Link to unknown</a>
                                                    <span class="Tooltip__arrow"></span>
                                                  </div>
                                                </div>

Advanced Floating Functionality

To enable the advanced floating functionality, you need to have activated feature flag for placement, activate the JS plugin, wrap your tooltip with an element having the data-spirit-element="tooltip-wrapper" data attribute, and add the data-spirit-placement-controlled attribute to your tooltip element to modify the styling of arrows and tooltip placement.


                                                
                                                <div class="spirit-feature-tooltip-enable-data-placement">
                                                  <div class="TooltipWrapper d-inline-block" data-spirit-element="tooltip-wrapper">
                                                    <button type="button" id="tooltip-trigger" data-spirit-toggle="tooltip" data-spirit-target="#floating-ui-example">
                                                      Toggle tooltip
                                                    </button>
                                                    <div
                                                      id="floating-ui-example"
                                                      class="Tooltip is-hidden"
                                                      data-spirit-placement="bottom"
                                                      data-spirit-placement-controlled
                                                    >
                                                      Hello there!
                                                      <span class="Tooltip__arrow" data-spirit-element="arrow"></span>
                                                    </div>
                                                  </div>
                                                </div>

👉 Please consult Floating UI documentation to understand how it works and to get an idea of all possible cases you may need to cover.

Floating UI Attributes

Attribute Type Default Required Description
data-spirit-enable-flipping-cross-axis [true | false] true Enables flipping on the cross axis, the axis perpendicular to main axis. For example top-end can be flipped to the top-start.
data-spirit-enable-flipping [true | false] true Enables [flippingfloating-ui-flip of the element’s placement when it starts to overflow its boundary area. For example top can be flipped to bottom.
data-spirit-enable-shifting [true | false] true Enables shifting of the element to keep it inside the boundary area by adjusting its position.
data-spirit-enable-sizing [true | false] true Enables sizing of the element to keep it inside the boundary area by setting the max width.
data-spirit-flip-fallback-axis-side-direction ["none" | "start" | "end" ] "none" Whether to allow [fallback to the opposite axis][floating-ui-flip-fallback-axis-side-direction] if no placements along the preferred placement axis fit, and if so, which side direction along that axis to choose. If necessary, it will fallback to the other direction.
data-spirit-flip-fallback-placements string - This describes a list of explicit placements to try if the initial placement doesn’t fit on the axes in which overflow is checked. For example you can set "top, right, bottom"
data-spirit-placement Placement Dictionary "bottom" Placement of tooltip
data-spirit-trigger ["click" | "hover" | "manual"] "click, hover" How tooltip is triggered: click, hover, manual. You may pass multiple triggers; separate them with a comma. If you pass manual, no event listener will be added, and you should provide your own toggle solution.

👆 All the attributes mentioned above can be also set as an object in the config attribute, like this: data-spirit-config='{"flip": "true", "flipFallbackPlacements": "top, right, bottom"}'. Please note that this configuration has lower priority than individual attributes and will be overwritten by them.

JavaScript API

Methods

Method Description
getInstance Static method which allows you to get the tooltip instance associated with a DOM. element
getOrCreateInstance Static method which allows you to get the tooltip instance associated with a DOM element, or create a new one in case it wasn’t initialized.
hide Hides an element’s tooltip. Returns to the caller before the tooltip has actually been hidden (i.e. before the hidden.tooltip event occurs). This is considered a “manual” triggering of the tooltip.
show Reveals an element’s tooltip. Returns to the caller before the tooltip has actually been shown (i.e. before the shown.tooltip event occurs). This is considered a “manual” triggering of the tooltip. Tooltips with zero-length titles are never displayed.
toggle Toggles an element’s tooltip. Returns to the caller before the tooltip has actually been shown or hidden (i.e. before the shown.tooltip or hidden.tooltip event occurs). This is considered a “manual” triggering of the tooltip.

                                                
                                                const tooltip = Tooltip.getInstance('#example'); // Returns a tooltip instance
                                                
                                                tooltip.show();

Events

Method Description
hidden.tooltip This event is fired when the hide instance has finished being hidden from the user.
hide.tooltip This event is fired immediately when the hide instance method has been called.
show.tooltip This event fires immediately when the show instance method is called.
shown.tooltip This event is fired when the show instance has finished being shown to the user.

                                                
                                                const myTooltipEl = document.getElementById('myTooltip');
                                                const tooltip = Tooltip.getOrCreateInstance(myTooltipEl);
                                                
                                                myTooltipEl.addEventListener('hidden.tooltip', () => {
                                                  // do something...
                                                });
                                                
                                                tooltip.hide();

[floating-ui-flip-floating-ui-flip-fallback-axis-side-direction]: https://floating-ui.com/docs/flip#fallbackaxissidedirection

Example