Back to Lit

07

packages/lit-dev-content/site/tutorials/content/tooltip/07.md

latest3.4 KB
Original Source

You've polished the tooltip's behavior with animations. Now it's time to ensure great performance.

Since a tooltip displays only when a user interacts with the target, the tooltip does not need to be created until interaction. If a page uses a lot of tooltips, which is not uncommon, adding this optimization can speed up initial page rendering by a meaningful amount.

To do this, you'll create a function users will call with a tooltip target element and a callback that will render tooltip content on demand when its needed.

Add a static method to the SimpleTooltip class called lazy. It will setup event listeners on the target element that listen on the same events used to trigger the tooltip. The listener creates the tooltip element and calls the user callback with it to fill in the content before showing it. Near the top of the class definition, add:

simple-tooltip.<ts-js></ts-js>

{% switchable-sample %}

ts
// Lazy creation
static lazy(target: Element, callback: (target: SimpleTooltip) => void) {
  const createTooltip = () => {
    const tooltip = document.createElement('simple-tooltip') as SimpleTooltip;
    callback(tooltip);
    target.parentNode!.insertBefore(tooltip, target.nextSibling);
    tooltip.show();
    // We only need to create the tooltip once, so ignore all future events.
    enterEvents.forEach(
      (eventName) => target.removeEventListener(eventName, createTooltip));
  };
  enterEvents.forEach(
    (eventName) => target.addEventListener(eventName, createTooltip));
}
js
// Lazy creation
static lazy(target, callback) {
  const createTooltip = () => {
    const tooltip = document.createElement('simple-tooltip');
    callback(tooltip);
    target.parentNode!.insertBefore(tooltip, target.nextSibling);
    tooltip.show();
    // We only need to create the tooltip once, so ignore all future events.
    enterEvents.forEach(
      (eventName) => target.removeEventListener(eventName, createTooltip));
  };
  enterEvents.forEach(
    (eventName) => target.addEventListener(eventName, createTooltip));
}

{% endswitchable-sample %}

Now open the <code>my-content.<ts-js></ts-js></code> module and change the greeting tooltip to use the lazy method. To do so, first remove the inline tooltip:

my-content.<ts-js></ts-js>

html
<p>
  <span id="greeting">Hello, ${this.name}! <span class="icon">info_outline</span></span>
</p>

Then define a firstUpdated lifecycle callback to setup the call to lazy.

{% switchable-sample %}

ts
import {SimpleTooltip} from './simple-tooltip.js';

@customElement('my-content')
export class MyContent extends LitElement {
  // ...
  firstUpdated() {
    const greeting = this.shadowRoot!.getElementById('greeting')!;
    SimpleTooltip.lazy(greeting, (tooltip: SimpleTooltip) => {
      tooltip.textContent = `${this.name}, there's coffee available in the lounge.`;
    });
  }
js
import {SimpleTooltip} from './simple-tooltip.js';

export class MyContent extends LitElement {
  // ...
  firstUpdated() {
    const greeting = this.shadowRoot.getElementById('greeting');
    SimpleTooltip.lazy(greeting, (tooltip) => {
      tooltip.textContent = `${this.name}, there's coffee available in the lounge.`;
    });
  }

{% endswitchable-sample %}

The tooltip for the greeting element should work the same now, but it's created on demand when one of the "enter" events is triggered. If you do this for all tooltips, you can ensure they don't impose a performance penalty on initial page render.