Building a Smart Tooltip Plugin in Oracle APEX

Modern enterprise applications often require contextual guidance for users. When screens
become complex, simple UI hints can significantly improve usability. One effective way to
achieve this is through tooltips small information boxes that appear when users hover over or
click on an element.


In this article, we will learn how to build a reusable Smart Tooltip Plugin in Oracle
APEX. This plugin allows developers to easily attach interactive tooltips anywhere in their
application, making interfaces more intuitive and user-friendly.

Introduction to the Smart Tooltip Plugin?

The Smart Tooltip Plugin is a custom Oracle APEX Item Plugin designed to display
contextual help through dynamic tooltips.
Instead of placing static help text across the page, developers can attach a tooltip to any label,
icon, or item. When a user hovers over or clicks the element, a tooltip appears with additional
information.
This improves:

  • User guidance
  • UI cleanliness
  • Application usability
  • Self-documentation of fields

Key Features of the Plugin

The Smart Tooltip Plugin includes several advanced capabilities.
Hover or Click Activation: Tooltips can appear when a user:

  • Hovers over an element
  • Clicks on an element

Rich HTML Content: The tooltip supports HTML formatting such as:

  • Bold text
  • Links
  • Images
  • Lists

Example:

Includes Base Salary + Allowances

Smart Positioning: The tooltip can appear in different positions relative to the element:

  • Top
  • Bottom
  • Left
  • Right
  • Auto (automatic positioning)

Custom Styling: Developers can configure:

  • Background colour
  • Text colour
  • Animation effects

Responsive Design: The tooltip works on:

  • Desktop browsers
  • Mobile devices

Performance Optimization: The plugin loads CSS and JavaScript only once, ensuring better
performance.

Plugin Architecture:
The plugin follows a modular design pattern combining PL/SQL, JavaScript, and CSS.

Plugin Components:

However, in this implementation, the JavaScript and CSS are embedded directly inside
the PL/SQL render function. This simplifies deployment and avoids external resource
loading issues.

Prerequisites

Before creating the plugin, ensure you have the following:

Software Requirements

  • Oracle APEX 19.1 or higher
  • Oracle Database 11g R2 or higher

Knowledge Requirements
Basic knowledge of:

  • PL/SQL
  • JavaScript
  • HTML / CSS
  • Oracle APEX plugin architecture

Creating the Plugin in Oracle APEX
Step 1: Create the Plugin

  1. Open Oracle APEX
  2. Go to Shared Components
  3. Click Plugins
  4. Click Create
  5. Choose:
    Plugin Type: Item
  6. Enter the plugin details. Example:
    Name: Smart Tooltip Plugin
    Internal Name: SMART.TOOLTIP.PLUGIN

Step 2: Define Plugin Attributes
Next, configure plugin attributes that allow developers to customize tooltip behavior

AttributeLabelPurpose
attribute_01Trigger ModeHover or Click
attribute_02PositionTooltip location
attribute_03Background ColorTooltip background
attribute_04Text ColorTooltip text color
attribute_05Tooltip ContentHTML content
attribute_06Show ArrowEnable arrow pointer
attribute_07Trigger DelayDelay before
showing
attribute_08Auto CloseAuto hide timer
attribute_09AnimationFade / Slide / None
attribute_10DismissibleAllow manual close

These attributes allow the plugin to be highly customizable without code changes.

Implementing the Render Function

The render function is the core of the plugin. It generates the HTML, injects CSS, and
initializes the JavaScript logic.
The procedure below is responsible for rendering the tooltip element.

PROCEDURE render_smart_tooltip (
p_item IN apex_plugin.t_item,
p_plugin IN apex_plugin.t_plugin,
p_param IN apex_plugin.t_item_render_param,
p_result IN OUT NOCOPY apex_plugin.t_item_render_result
)
IS
l_trigger VARCHAR2(20) := NVL(LOWER(p_item.attribute_01), 'hover');
l_position VARCHAR2(20) := NVL(LOWER(p_item.attribute_02), 'top');
l_bg VARCHAR2(20) := NVL(p_item.attribute_03, '#333333');
l_fg VARCHAR2(20) := NVL(p_item.attribute_04, '#ffffff');
l_content VARCHAR2(4000) := NVL(p_item.attribute_05, 'Tooltip text here');
l_anim VARCHAR2(10) := NVL(LOWER(p_item.attribute_09), 'fade');
l_autoclose NUMBER := NVL(TO_NUMBER(p_item.attribute_08), 0);
l_trigger_attr VARCHAR2(10);
l_id VARCHAR2(200) := p_item.id;
l_label VARCHAR2(4000);
BEGIN
l_label := CASE WHEN p_param.value IS NOT NULL
THEN apex_escape.html(p_param.value)
ELSE '&#9432:'
END;
l_trigger_attr := CASE WHEN l_trigger = 'click' THEN 'click' ELSE 'hover' END;
htp.p('<script>');
 htp.p('(function(){');
 htp.p(' if(document.getElementById("_stt_css")){return;}');
 htp.p(' var s=document.createElement("style");');
 htp.p(' s.id="_stt_css";');
 htp.p(' s.innerHTML=');
 htp.p(' ".stt-trigger{cursor:pointer;display:inline-block;vertical-align:middle;font-size:16px;}"');
 htp.p(' +".stt-trigger:focus{outline:2px solid #0066cc;outline-offset:2px;}"');
 htp.p(' +"#_stt_box{position:fixed;display:none;padding:10px 14px;border-radius:6px;"');
 htp.p(' +"font-size:13px;line-height:1.6;max-width:280px;"');
 htp.p(' +"z-index:2147483647;box-shadow:0 6px 20px rgba(0,0,0,0.35);"');


htp.p(' +"word-wrap:break-word;font-family:Arial,sans-serif;}"');
 htp.p(' +"#_stt_arrow{position:absolute;width:0;height:0;border-style:solid;}";');
 htp.p(' document.head.appendChild(s);');
 htp.p('}());');
 htp.p('</script>');
 htp.p('<script>');
 htp.p('(function(){');
 htp.p(' if(typeof window._sttShow!=="undefined"){return;}');
 htp.p(' function _getBox(){');
 htp.p(' var b=document.getElementById("_stt_box");');
 htp.p(' if(!b){');
 htp.p(' b=document.createElement("div");');
 htp.p(' b.id="_stt_box";');
 htp.p(' var ar=document.createElement("div");');
 htp.p(' ar.id="_stt_arrow";');
 htp.p(' b.appendChild(ar);');
 htp.p(' var bd=document.createElement("div");');
 htp.p(' bd.id="_stt_body";');
 htp.p(' b.appendChild(bd);');
 htp.p(' document.body.appendChild(b);');
 htp.p(' }');
 htp.p(' return b;');
 htp.p(' }');
htp.p(' function _place(el,pos,bg){');
 htp.p(' var b=_getBox();');
 htp.p(' var r=el.getBoundingClientRect();');
 htp.p(' b.style.visibility="hidden";');
 htp.p(' b.style.display="block";');
 htp.p(' var bW=b.offsetWidth||220;');
 htp.p(' var bH=b.offsetHeight||44;');
 htp.p(' b.style.visibility="";');
 htp.p(' b.style.display="none";');
 htp.p(' var wW=window.innerWidth;');
 htp.p(' var wH=window.innerHeight;');
 htp.p(' var t,l;');
 htp.p(' var ar=document.getElementById("_stt_arrow");');
 htp.p(' ar.style.cssText="position:absolute;width:0;height:0;border-style:solid;";');
 htp.p(' if(pos==="auto"){pos=r.top>bH+16?"top":"bottom";}');
 htp.p(' if(pos==="top"){');
 htp.p(' t=r.top-bH-10;');
 htp.p(' l=r.left+(r.width-bW)/2;');
 htp.p(' ar.style.bottom="-6px";');
 htp.p(' ar.style.left="50%";');
 htp.p(' ar.style.marginLeft="-6px";');
 htp.p(' ar.style.borderWidth="6px 6px 0 6px";');
 htp.p(' ar.style.borderColor=bg+" transparent transparent transparent";');
 htp.p(' }else if(pos==="bottom"){');
 htp.p(' t=r.bottom+10;');
 htp.p(' l=r.left+(r.width-bW)/2;');
htp.p(' ar.style.top="-6px";');
 htp.p(' ar.style.left="50%";');
 htp.p(' ar.style.marginLeft="-6px";');
 htp.p(' ar.style.borderWidth="0 6px 6px 6px";');
 htp.p(' ar.style.borderColor="transparent transparent "+bg+" transparent";');
 htp.p(' }else if(pos==="left"){');
 htp.p(' t=r.top+(r.height-bH)/2;');
 htp.p(' l=r.left-bW-10;');
 htp.p(' ar.style.top="50%";');
 htp.p(' ar.style.right="-6px";');
 htp.p(' ar.style.marginTop="-6px";');
 htp.p(' ar.style.borderWidth="6px 0 6px 6px";');
 htp.p(' ar.style.borderColor="transparent transparent transparent "+bg;');
 htp.p(' }else{');
 htp.p(' t=r.top+(r.height-bH)/2;');
 htp.p(' l=r.right+10;');
 htp.p(' ar.style.top="50%";');
 htp.p(' ar.style.left="-6px";');
 htp.p(' ar.style.marginTop="-6px";');
 htp.p(' ar.style.borderWidth="6px 6px 6px 0";');
 htp.p(' ar.style.borderColor="transparent "+bg+" transparent transparent";');
 htp.p(' }');
 htp.p(' l=Math.max(5,Math.min(l,wW-bW-5));');
 htp.p(' t=Math.max(5,Math.min(t,wH-bH-5));');
 htp.p(' b.style.left=l+"px";');
 htp.p(' b.style.top=t+"px";');

htp.p(‘ }’);
htp.p(‘ window._sttShow=function(el){‘);
htp.p(‘ clearTimeout(window._sttHT);’);
htp.p(‘ clearTimeout(window._sttAT);’);
htp.p(‘ var content = el.getAttribute(“data-stt-content”);’);
htp.p(‘ var pos = el.getAttribute(“data-stt-pos”) ||”top”;’);
htp.p(‘ var bg = el.getAttribute(“data-stt-bg”) ||”#333″;’);
htp.p(‘ var fg = el.getAttribute(“data-stt-fg”) ||”#fff”;’);
htp.p(‘ var anim = el.getAttribute(“data-stt-anim”) ||”fade”;’);
htp.p(‘ var ac = parseInt(el.getAttribute(“data-stt-ac”)||”0″,10);’);
htp.p(‘ var b=_getBox();’);
htp.p(‘ b.style.backgroundColor=bg;’);
htp.p(‘ b.style.color=fg;’);
htp.p(‘ document.getElementById(“_stt_body”).innerHTML=content;’);
htp.p(‘ _place(el,pos,bg);’);
htp.p(‘ b.style.display=”block”;’);
htp.p(‘ if(anim===”fade”){‘);
htp.p(‘ b.style.transition=”opacity 0.2s ease”;’);
htp.p(‘ b.style.opacity=”0″;’);
htp.p(‘ setTimeout(function(){b.style.opacity=”1″;},10);’);
htp.p(‘ }else{‘);
htp.p(‘ b.style.transition=””;’);
htp.p(‘ b.style.opacity=”1″;’);
htp.p(‘ }’);
htp.p(‘ if(ac>0){‘);
htp.p(‘ window._sttAT=setTimeout(function(){window._sttHide();},ac);’);

htp.p(‘ }’);
htp.p(‘ };’);
htp.p(‘ window._sttHide=function(){‘);
htp.p(‘ clearTimeout(window._sttAT);’);
htp.p(‘ var b=document.getElementById(“_stt_box”);’);
htp.p(‘ if(!b||b.style.display===”none”){return;}’);
htp.p(‘ b.style.transition=”opacity 0.15s ease”;’);
htp.p(‘ b.style.opacity=”0″;’);
htp.p(‘ window._sttHT=setTimeout(function(){‘);
htp.p(‘ b.style.display=”none”;’);
htp.p(‘ },160);’);
htp.p(‘ };’);
htp.p(‘ window._sttToggle=function(el){‘);
htp.p(‘ var b=document.getElementById(“_stt_box”);’);
htp.p(‘ if(b&&b.style.display===”block”){‘);
htp.p(‘ window._sttHide();’);
htp.p(‘ }else{‘);
htp.p(‘ window._sttShow(el);’);
htp.p(‘ }’);
htp.p(‘ };’);
htp.p(‘}());’);
htp.p(”);
IF l_trigger_attr = ‘hover’ THEN
htp.p(‘
<span’

|| ‘ id=”‘ || apex_escape.html_attribute(l_id) || ‘”‘
|| ‘ class=”stt-trigger”‘
|| ‘ tabindex=”0″‘
|| ‘ role=”button”‘
|| ‘ aria-label=”More information”‘
|| ‘ data-stt-content=”‘ || apex_escape.html_attribute(l_content) || ‘”‘
|| ‘ data-stt-pos=”‘ || apex_escape.html_attribute(l_position) || ‘”‘
|| ‘ data-stt-bg=”‘ || apex_escape.html_attribute(l_bg) || ‘”‘
|| ‘ data-stt-fg=”‘ || apex_escape.html_attribute(l_fg) || ‘”‘
|| ‘ data-stt-anim=”‘ || apex_escape.html_attribute(l_anim) || ‘”‘
|| ‘ data-stt-ac=”‘ || TO_CHAR(l_autoclose) || ‘”‘
|| ‘ onmouseenter=”_sttShow(this)”‘
|| ‘ onmouseleave=”_sttHide()”‘
|| ‘ onfocus=”_sttShow(this)”‘
|| ‘ onblur=”_sttHide()”‘
|| ‘>’
|| l_label
|| ”);
ELSE
htp.p(‘<span’
|| ‘ id=”‘ || apex_escape.html_attribute(l_id) || ‘”‘
|| ‘ class=”stt-trigger”‘
|| ‘ tabindex=”0″‘
|| ‘ role=”button”‘
|| ‘ aria-label=”More information”‘
|| ‘ data-stt-content=”‘ || apex_escape.html_attribute(l_content) || ‘”

|| ‘ data-stt-pos=”‘ || apex_escape.html_attribute(l_position) || ‘”‘
|| ‘ data-stt-bg=”‘ || apex_escape.html_attribute(l_bg) || ‘”‘
|| ‘ data-stt-fg=”‘ || apex_escape.html_attribute(l_fg) || ‘”‘
|| ‘ data-stt-anim=”‘ || apex_escape.html_attribute(l_anim) || ‘”‘
|| ‘ data-stt-ac=”‘ || TO_CHAR(l_autoclose) || ‘”‘
|| ‘ onclick=”_sttToggle(this)”‘
|| ‘>’
|| l_label
|| ”);
END IF;
END render_smart_tooltip;

The render function performs the following tasks:

  • Reads plugin attributes
  • Handles user interactions
  • Generates tooltip HTML
  • Injects CSS styling
  • Registers JavaScript functions

How the plugin works

The plugin uses a data attribute driven approach.
Instead of embedding complex JavaScript objects in HTML, the tooltip configuration is
stored in data-* attributes.
Example:

<span
class="stt-trigger"
data-stt-content="Includes base salary and allowances"
data-stt-pos="top"
data-stt-bg="#333"
data-stt-fg="#fff">
</span>

When the user interacts with the element, JavaScript reads these attributes and renders the
tooltip dynamically.

This approach prevents JavaScript quoting issues, which were causing errors in earlier
implementations.

Using the Plugin in Oracle APEX

After installing the plugin, using it is very simple.
Step 1: Create an Item on a page.
Step 2: Select Type
Smart Tooltip Plugin
Step 3: Configure the attributes.
Example configuration:
Trigger Mode: Hover
Position: Top
Background Color: #333
Text Color: #fff
Tooltip Content: Includes base salary + allowances
Animation: Fade
Auto Close: 5000

Testing the plugin in APEX
After implementing the plugin, perform the following tests.
Functional Tests

  • Hover trigger works
  • Click trigger works
  • Tooltip positioning is correct
  • Animation works

UI Tests

  • Works on desktop
  • Works on mobile
  • Tooltip stays within viewport

Performance Tests: Ensure:

  • CSS loads only once
  • JavaScript functions are not duplicated

Deployment
To deploy the plugin:

  1. Export the plugin from APEX
  2. Save the SQL file
  3. Import it into another workspace

This makes the plugin fully reusable across applications.


Troubleshooting
Tooltip Not Appearing: Check:

  • Plugin attributes
  • JavaScript console errors

Tooltip Position Incorrect: Verify:

  • Position attribute
  • Viewport size calculations

Styling Issues: Ensure CSS is loaded properly in the render function.

Conclusion

The Smart Tooltip Plugin is a powerful enhancement for Oracle APEX applications. It
enables developers to add dynamic contextual help across the interface with minimal
effort.
By combining PL/SQL, JavaScript, and CSS, the plugin provides a reusable solution that
improves both user experience and application’s maintainability.
If you are building enterprise applications in Oracle APEX, integrating a smart tooltip system
can significantly improve usability while keeping your interface clean and professional.
Author: Sushree Manaswini Biswal, Oracle APEX consultant