<!DOCTYPE HTML>
<html style="height: 100%;">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>Demo</title>
    <script id="sap-ui-bootstrap"
      src="https://sdk.openui5.org/resources/sap-ui-core.js"
      data-sap-ui-libs="sap.ui.core,sap.m"
      data-sap-ui-theme="sap_horizon"
      data-sap-ui-async="true"
      data-sap-ui-oninit="onUI5Init"
      data-sap-ui-resourceroots='{"demo": "./"}'
      data-sap-ui-compatversion="edge"
      data-sap-ui-excludejquerycompat="true"
      data-sap-ui-xx-waitfortheme="init"
    ></script>
    <script>
      globalThis.onUI5Init = () => sap.ui.require([
        "sap/ui/core/mvc/XMLView",
        "sap/ui/model/json/JSONModel",
      ], (XMLView, JSONModel) => XMLView.create({
        viewName: "demo.view.App",
        height: "100%",
        models: new JSONModel(sap.ui.require.toUrl("demo/data.json")),
      }).then(view => view.placeAt("content")));
    </script>
  </head>
  <body class="sapUiBody" id="content"></body>
</html>
sap.ui.define([
  "sap/ui/core/TooltipBase",
  "./TooltipRenderer",
], function (TooltipBase, TooltipRenderer) {
  "use strict";

  /**
   * ⚠️ NOTE ⚠️
   * - This is a minimal sample. It's incomplete and TooltipBase has issues.
   * - Tooltips should never contain critical information.
   * - Tooltips shouldn't contain redundant information either.
   * - Only desktop users might find tooltips useful. Not intended for mobile.
   * - UX guideline: https://experience.sap.com/fiori-design-web/using-tooltips
   */

  return TooltipBase.extend("demo.control.Tooltip", {
    renderer: TooltipRenderer,
    metadata: {
      interfaces: [
        "sap.ui.core.PopupInterface",
      ],
      properties: {
        "width": {
          type: "sap.ui.core.CSSSize",
          defaultValue: "100%",
        },
        // ... and other properties inherited from TooltipBase such as "text".
        // See https://openui5.hana.ondemand.com/api/sap.ui.core.TooltipBase
      },
      aggregations: {
        "content": {
          type: "sap.ui.core.Control",
          multiple: false,
          bindable: true,
        },
      },
      defaultAggregation: "content",
    },

    // Issue: https://github.com/SAP/openui5/issues/3168
    // This whole tooltip is added as a delegate to the owner. Not sure why.
    // Thus the events here are handled for the owner as well. E.g.:
    onfocusin: function() {
      // Will be called on focus of this tooltip. But ...
      // Will be called on focus of the owner too, even if this is not rendered.
      debugger;
      TooltipBase.prototype.onfocusin.apply(this, arguments);
      // Enable "Emulate a focused page" for better debugging.
      // See https://stackoverflow.com/a/65188771/5846045
    },
    onlocalizationChanged: function() {
      debugger; // https://github.com/SAP/openui5/issues/3168
    },
    onThemeChanged: function() {
      debugger; // https://github.com/SAP/openui5/issues/3168
    },

  });
});
sap.ui.define([
  "sap/ui/core/Renderer",
], function(Renderer) {
  "use strict";

  return Renderer.extend("demo.control.TooltipRenderer", {
    apiVersion: 2,
    render: function(renderManager, control) {
      // Issue: render function is called twice.
      // See: https://github.com/SAP/openui5/issues/3169
      // Update: fixed since 1.88

      const child = control.getAggregation("content");
      if (child && child.isA("sap.ui.core.Control")) {
        renderManager.openStart("div", control)
          .accessibilityState(control, { role: "tooltip" })
          .style("width", control.getWidth())
          .style("max-width", "23rem")
          .class("sapMPopup-CTX")
          .openEnd()
          .renderControl(child)
          .close("div");
      } else {
        renderManager.openStart("span", control)
          .accessibilityState(control, { role: "tooltip" })
          .style("max-width", "24rem")
          // .style("display", "inline-block")
          .style("word-wrap", "break-word")
          .style("width", "auto")
          .style("padding", "0.75rem")
          .class("sapThemeBaseBG-asBackgroundColor")
          .class("sapMPopup-CTX")
          .openEnd()
          .text(control.getText())
          .close("span");
      }
    },

  });
});
<mvc:View xmlns:mvc="sap.ui.core.mvc"
  xmlns="sap.m"
  xmlns:my="demo.control"
  displayBlock="true"
>
  <App autoFocus="false">
    <Page showHeader="false" backgroundDesign="List">
      <List>
        <StandardListItem title="Native tooltip" tooltip="From your browser" />
        <StandardListItem title="Custom Tooltip with opening delay of {/openDelay}ms">
          <tooltip>
            <my:Tooltip id="textTooltip"
              text="{/text}"
              openDelay="{/openDelay}"
              offset="10 -5"
              closeDuration="0"
            />
          </tooltip>
        </StandardListItem>
        <StandardListItem title="Custom Tooltip with another control">
          <tooltip>
            <my:Tooltip id="richerTooltip" closeDuration="0">
              <List items="{/items}">
                <StandardListItem
                  icon="{icon}"
                  title="{text}"
                  description="{description}"
                  iconInset="false"
                />
              </List>
            </my:Tooltip>
          </tooltip>
        </StandardListItem>
      </List>
    </Page>
  </App>
</mvc:View>
{
  "text": "My awesome custom tooltip!",
  "openDelay": 100,
  "items": [
    {
      "text": "Title 1",
      "icon": "https://openui5.org/654aad3012a144881ab07c0bbdd26eb8/phenix_red.svg",
      "description": "Wow"
    },
    {
      "text": "Title 2",
      "icon": "https://openui5.org/5bdd288371ed8100415f04563acc8dfe/phenix_blue.svg",
      "description":  "Such"
    },
    {
      "text": "Title 3",
      "icon": "sap-icon://sap-ui5",
      "description": "List"
    }
  ]
}