I've a VF Page which uses a Apex StandardSetController() to display the list of a Standard Object Records(Case in my Page). The mini page layout which is a standard functionality from Salesforce has some CSS issues.

On Hover, the mini page layout appears as expected but the position is absolute. I've scroll-able view, so when I hover on records after scrolling(on those which were hidden previously), the mini page layout is shown at the absolute position and not at the current position.

I'm sure that it has nothing to do with the StandardSetController(). Is there a CSS patch for this situation. Will it be a proper way to alter the Standard CSS since the classes and the CSS might be changed from the Salesforce side in a newer releases?

  • Have you tried submitting a bug for this? Seems like a pretty valid use case that should be handled by Salesforce already Feb 15, 2013 at 16:36
  • You mean by raising a case? No. I didn't. Feb 15, 2013 at 17:26
  • Correct, definitely helpful to have a workaround the answer suggested, but this feels like something salesforce should be fixing Feb 15, 2013 at 19:18

4 Answers 4


I've run into this issue before as well. It seems to be a combination of Javascript and CSS. Looking at their Javascript, this is the function that appears to be called

function LookupHoverDetail(a, b) {
    this.id = a;
    this.width = LookupHoverDetail.STANDARD_BUBBLE_WIDTH;
    this.bubbleOffset = Sfdc.userAgent.isIE6 ? 5 : 14;
    this.height = LookupHoverDetail.STANDARD_BUBBLE_HEIGHT;
    this.hover = document.createElement("div");
    this.hover.id = a + "Hover";
    this.hover.className = "individualPalette lookupHoverDetail lookupHoverDetailLoading lookupHoverDetailOverridable";
    this.hover.innerHTML = '<div class="topLeft"><div class="bPageBlock"><div class="pbBody">' + LC.getLabel("Global", "loading") + '<div><div class="pbFooter"><div class="bg"><div></div></div><div>';
    var c = this;
    addEvent(this.hover, "mouseover", function () {
    }, true);
    addEvent(this.hover, "mouseout", function () {
    }, true);
    this.hover = new iframeShim(this.hover);
    this.originalClass = "";
    this.fadingIn = this.fadingOut = null;
    this.loaderURL = b;
    this.loaded = false
LookupHoverDetail.STANDARD_BUBBLE_WIDTH = 302;
LookupHoverDetail.STANDARD_BUBBLE_HEIGHT = 262;
LookupHoverDetail.SHOW_DELAY = 800;
LookupHoverDetail.HIDE_DELAY = 250;
LookupHoverDetail.stopLoading = false;
LookupHoverDetail.hovers = {};
LookupHoverDetail.getHover = function (a, b) {
    var c = window.Shepherd;
    if (c && b) b = c.fixRetUrl(b);
    if (LookupHoverDetail.hovers[a]) return LookupHoverDetail.hovers[a];
    c = new LookupHoverDetail(a, b);
    return LookupHoverDetail.hovers[a] = c
LookupHoverDetail.hideAllHovers = function () {
    var a = LookupHoverDetail.hovers,
    for (b in a) a.hasOwnProperty(b) && a[b].hide()
LookupHoverDetail.prototype.show = function () {
    if (this.fadingOut) {
        this.fadingOut = null
    } else {
        var a = this;
        if (!this.fadingIn) this.fadingIn = setTimeout(function () {
        }, LookupHoverDetail.SHOW_DELAY)
LookupHoverDetail.prototype.showNow = function () {
    if (!this.loaded) if (this.loaderURL != null) {
        var a = this;
        Sfdc.Ajax.get(this.loaderURL, function (b) {
        }, {
            failure: function (b) {
    } else return;
    this.hover.setStyle("visibility", "visible");
    this.fadingIn = null
LookupHoverDetail.prototype.hide = function () {
    if (this.fadingIn) {
        this.fadingIn = null
    } else {
        var a = this;
        this.fadingOut = setTimeout(function () {
        }, LookupHoverDetail.HIDE_DELAY)
LookupHoverDetail.prototype.hideNow = function () {
    this.hover.setStyle("visibility", "hidden");
    this.fadingOut = null
LookupHoverDetail.prototype.load = function (a) {
    this.hover.div.innerHTML = a;
    this.originalClass = this.hover.div.firstChild.className;
    this.height = this.hover.div.offsetHeight;
    delStyleClass(this.hover.div, "lookupHoverDetailLoading");
    this.loaded = true
LookupHoverDetail.prototype.position = function () {
    var a = getElementByIdCS(this.id),
        b = getObjX(a),
        c = getObjY(a),
        d = a.offsetWidth,
        e = a.offsetHeight,
        f = getScrollX(),
        g = getScrollY(),
        h = getWindowWidth(),
        i = getWindowHeight();
    a = this.originalClass + " ";
    if (c + e + this.height < g + i) {
        a += "top";
        c += e
    } else {
        a += "bottom";
        c -= this.height
    if (b + d - this.bubbleOffset + this.width < f + h) {
        a += "Left";
        b = b + d / 2 - this.bubbleOffset
    } else {
        a += "Right";
        b = b + d / 2 - this.width
    this.hover.setStyle("left", b + "px");
    this.hover.setStyle("top", c + "px");
    this.hover.div.firstChild.className = a;
    if (this.hover.div.firstChild) if (b = Util.hasStyleEndsWith(this.hover.div.firstChild, "Override")) {
        delStyleClass(this.hover.div, "lookupHoverDetailOverridable");
        delStyleClass(this.hover.div.firstChild, b);
        addStyleClass(this.hover.div, b)

I would guess that Salesforce most likely uses the same ID for the same object referenced twice on a page (so if you have a lookup field to the same object twice on the page, they probably share the same ID), so when this LookupHoverDetail method is used, it looks for the first instance in the DOM which is at the top of the page.

To be completely honest with you, I am not sure how you can fix this. You will need to override Salesforce's included Javascript.

  • Since salesforce provides the hover functionality by default when a reference is used (obj_ref__c), is it possible to report a case, an idea or something to address this issue? Because, the same applies in every other visualforce page. Sep 27, 2012 at 17:44
  • 1
    I did some quick searching and really couldn't find an idea that was already started. I would suggest starting something up if that is the course you would like to take success.salesforce.com/ideaHome?c=09a30000000D9xtAAC Sep 27, 2012 at 20:28
  • Can you say What I need to do for making this happen.Because I copied this in script tabg in Vf page.But didnt see any change. How to override Salesforce's included Javascript.
    – Arun SFDC
    Jun 13, 2013 at 13:22

I've found the solution for this issue. The point is to give the popup an unique id. So we can't use the object reference id because it is a shared value on the page (like @JesseAltman said in his answer). Now we need to generate this ID manually and use an imitation of the popup. For that i will use an apex:variable tag to generate ID if this form: hover123:


<apex:outputPanel style="width:300px;" layout="block">

<!-- Here defining a new variable for the fake id -->
<apex:variable value="{!0}" var="rowNumber" />

<apex:pageBlock mode="maindetail">
    <apex:pageBlockTable value="{!accs}" var="a">
        <apex:column value="{!a.name}"/>

        <apex:column headerValue="Some header">
            <a href="/{!a.test2__r.id}" id="hover{!rowNumber}" 
                                        onfocus="LookupHoverDetail.getHover('hover{!rowNumber}', '/{!a.test2__r.id}/m?retURL=%2F{!a.test2__r.id}&isAjaxRequest=1').show();" 
                                        onmouseover="LookupHoverDetail.getHover('hover{!rowNumber}', '/{!a.test2__r.id}/m?retURL=%2F{!a.test2__r.id}&isAjaxRequest=1').show();">

        <apex:column headerValue="1">
            <!-- Increasing the value of the variable -->
            <apex:variable var="rowNumber" value="{!rowNumber + 1}" />



Apex (here i have the same test2__c reference in each account):

public with sharing class MyClass {

    // Just a list with some accounts
    public List<Account> accs { get; set; }

    public MyClass() { 
        accs = [Select id, test2__c, test2__r.id, test2__r.name, Name 
                From Account 
                Limit 100];

This will looks like this:

enter image description here


I came across this post trying to find a solution to the same issue, In my case i found that the popup was selecting the correct ID along the x axis but moving the position on the popup outside of the panel i wanted. So when i highlighted the linked item if it was say 800px on a scroller. It would move the popup to 800px outside the scroller.

This was the first issue I found. There were also ID issues along the X and Y for different commandLinks & when I reordered my page the popups would again be scrambled.

I worked out that the broken / buggy SalesForce code was within LookupHoverDetail.prototype.position. In here we were returning getObjX and getObjY wrongly.

So within my visualforce page I placed some overwriting code to replace the wrong possitions.

function getObjX(a) {
    var left = 0;       
        left += (a.offsetLeft - a.scrollLeft + a.clientLeft);
        a = a.offsetParent;
    return left;
function getObjY(a) {
    var top = 0;        
        top += (a.offsetTop - a.scrollTop + a.clientTop);
        a = a.offsetParent;
    return top;

Next I had to deal with the ID's being non-unique, I call this function after every Ajax event so that if I order the page, the Id's are to the correct links still. This function will execute at the same time as the others on load.

function fixSalesforce() {
    $FFDC('.lineItem A').each(function(index){
        var me = $FFDC(this);
        var aId = me.attr('id');
        if (aId != null){
        var trId = me.closest('tr').attr('id');
            if (aId.indexOf(trId) != 0){
            var newId = trId + aId;
            me.attr('id', newId);
            me.attr('onmouseover', me.attr('onmouseover').replace( new RegExp(aId, 'g' ), newId));
            me.attr('onmouseout', me.attr('onmouseout').replace( new RegExp(aId, 'g' ), newId));
            me.attr('onfocus', me.attr('onfocus').replace( new RegExp(aId, 'g' ), newId));
            me.attr('onblur', me.attr('onblur').replace( new RegExp(aId, 'g' ), newId));

The aim of the above function is to make the ID's unique by prefixing them with the row ID which I put on the TR.

      <apex:variable value="{!0}" var="tRow" /> 
      <apex:repeat var="tl"value="{!viewState.BankStatement.TransactionLineItems}"id="tRow1"> 
      <tr id="tRow{!tRow}" class="lineItem{!IF(tl.isChecked,'selected','')}">
      <apex:variable var="tRow"value="{!tRow+1}"/>

Within all CommandLinks I then placed onComplete="Refresh();"

This is a function that will call the fixSalesforce() function from earlier.


For those who are still struck, once your page loads, have below function executed:check my blog

function modifyIDS(){
            j$("a[id *='lookup']").each(function(index){
                var newID = "referencedField"+index;
                var elem = j$(this);
                var fullHTML = elem[0].outerHTML;
                var oldID = elem.attr('id');
                 console.log('modifyIDS2' +oldID);
                var regex = new RegExp( oldID, 'g');
               // console.log(fullHTML);


                    elem[0].outerHTML = fullHTML.replace(regex,
                    console.log('error occured: '+e);

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .