Repositioning the Datatable Tooltip

According to the Docs, I should be able to style the tooltip with CSS e.g.:

css=[{
        'selector': '.dash-table-tooltip',
        'rule': 'background-color: grey; font-family: monospace; color: white'
    }],

I would like to do so since positioning the tooltip below the cell interferes with cell dropdowns.

I tried manually repositioning using:

css=[{
        'selector': '.dash-table-tooltip',
        'rule': 'position: relative; left: -50px'
    }],

But that still doesn’t move the “container” it is in:
enter image description here

How can I shift the whole container?
SO Post: python - Plotly Dash: Repositioning the Datatable Tooltip - Stack Overflow
@JZbinden

1 Like

Hi there,

Your css rule does exactly what you would expect it to do. Your problem arises because the tooltip is actually multiple nested elements, of which you are moving the innermost one by 50px.

The “selector” class you are interested in would be dash-tooltip or one of its descendants.
Unfortunately the element disappears immediately from the browser inspector when leaving with the mouse and I don’t know how to make it stick, so I can’t really tell you how it’s organized inside this first container…

Shifting the container by a fixed value could however prove to be messy, as its position is set in absolute coordinates in the internal CSS rules.

I don’t know what you’re planning to do, but could it be a solution to set the width of your tooltip (See my last answer here) and padding your dropdown values via CSS so that the tooltip will overlap this empty padding? From your screenshot it looks like you have more than enough space to arrange things without necessarily having to touch the tooltip position.

It could also be cool to have the tooltip pop up above the cell instead of below, but I personally didn’t have the need for it and never tried figuring out if it’s possible. You may have to tag the core devs around @adamschroeder to find out more about this.

Good luck!

Thanks so much for your response. Unfortunately I am also hoping to make several lines of text - I was just using the example to demonstrate (if you know how to do carriage returns in the tooltip that’d be a bonus for me lol).

I’m planning to look for the source code is the dash repo for the default css on the container - I found what you pointed out accidentally in the docs today about the separate container.

Here is the source css:


.dash-tooltip {
    border: 1px solid #e4e4e4;
    border-radius: 5px;
    position: absolute;
    z-index: 500;

    .dash-table-tooltip {
        position: relative;
        background-color: #f6f6f6;
        max-width: 300px;
        min-width: 300px;
        padding: 2px 10px;
    }

    &[data-attr-anchor='top'] {
        margin-top: 10px;

        &:after, &:before {
            bottom: 100%;
            left: 50%;
            border: solid transparent;
            content: " ";
            height: 0;
            width: 0;
            position: absolute;
            pointer-events: none;
        }

        &:after {
            border-color: transparent;
            border-bottom-color: #f6f6f6;
            border-width: 8px;
            margin-left: -8px;
        }

        &:before {
            border-color: transparent;
            border-bottom-color: #e4e4e4;
            border-width: 9px;
            margin-left: -9px;
        }
    }

    &[data-attr-anchor='bottom'] {
        margin-bottom: 10px;

        &:after, &:before {
            top: 100%;
            left: 50%;
            border: solid transparent;
            content: " ";
            height: 0;
            width: 0;
            position: absolute;
            pointer-events: none;
        }

        &:after {
            border-color: transparent;
            border-top-color: #f6f6f6;
            border-width: 8px;
            margin-left: -8px;
        }
        &:before {
            border-color: transparent;
            border-top-color: #e4e4e4;
            border-width: 9px;
            margin-left: -9px;
        }
    }
}

I can read some of it but can’t say I understand everything that’s going on here lol

Not sure if this works for carriage returns, but I guess you tried the obvious \n and <br> ?

Yeah I am not a web dev either, so my understanding of this is also limited. But anyhow I would assume that most of the relevant code would be in the React/JS files that define these elements. It’s much easier to have the tooltip pop up at the right position when handling this in JS.

I’ll likely be digging a bit myself for this, I’ll make sure to come back if I find something.

1 Like

@sterlingbutters @JZbinden

To format the text inside the tootlip, you can use \n for a new line - or you can use Markdown. You can see examples in the docs here: DataTable Tooltips | Dash for Python Documentation | Plotly

For example: the **over** will dispaly as over

'goal': {'value': '9M **over** Goal', 'type': 'markdown'}

Here is plain text:

 'address': [
        '3000 Mall View Road, Suite 1107\n\nBakersfield, CA\n\n93306',
        '2130 Center Street, Suite 102\n\nBerkeley, CA\n\n94704',
        '652 Pine Knot Avenue\n\nBig Bear Lake, CA\n\n92315'
    ]

I’m wondering what would happen if I just changed this:

export enum Arrow {
    Bottom = 'bottom',
    Left = 'left',
    Right = 'right',
    Top = 'top'
}

To this:

export enum Arrow {
    Left = 'left',
    Right = 'right',
    Top = 'top'
}

And/or making the css the same for the ‘top’ and ‘bottom’ attribute selectors (making them both the ‘top’). What I don’t understand is why there is left/right arrows defined in the React code but no css for them

Here:

@AnnMarieW Yup none of
<br> (md and str)
\n (str)
\ (md)
<sp><sp> (md)
&#13; (str)

work for me. Not sure what the deal is

@sterlingbutters When you run the examples from the docs locally, do they work for you? Can you make a minimal example that replicates the problem?

df = pd.DataFrame({
    'shop': ['Bakersfield', 'Berkely', 'Big Bear Lake'],
    'sales': [3, 1, 5],
    'goal': [10, 1, 4],
    'address': [
        '3000 Mall View Road, Suite 1107 Bakersfield, CA 93306',
        '2130 Center Street, Suite 102 Berkeley, CA 94704',
        '652 Pine Knot Avenue Big Bear Lake, CA 92315'
    ]
})

app.layout = html.Div([
    dash_table.DataTable(
    id='test-table',
    data=df.to_dict('records'),
    columns=[{'id': c, 'name': c} for c in ['shop', 'sales', 'goal']],
    tooltip_data=[{
        'shop': {'value': row['address'], 'type': 'markdown'},
        'sales': {
            'value': 'Sales were **{} {}** than the goal'.format(
                str(abs(row['goal'] - row['sales'])),
                'less' if row['goal'] > row['sales'] else 'more'
            ),
            'type': 'markdown'
        },
        'goal': 'Goal was {}'.format(
            'not achieved' if row['goal'] > row['sales'] else 'achieved'
        ),
    } for row in df.to_dict('records')],

    tooltip_delay=0,
    tooltip_duration=None
), html.Button("Test", id='test')]
    )


@app.callback(
    Output('test-table', 'tooltip_data'),
    Input('test', "n_clicks"),
    State('test-table', 'tooltip_data')
)
def change_tooltips(n_clicks, tooltip_data):
    
    if n_clicks:
        new_tooltip_data = []
        for tip in tooltip_data:
            tip['shop']['value'] = tip['shop']['value'].replace(",", "\n") # works with \n\n instead of \n
            new_tooltip_data.append(tip)
            
    else:
        new_tooltip_data = tooltip_data
    
    print(new_tooltip_data)
    return new_tooltip_data

So interestingly it seems to only work when I do \n\n i.e. \n alone does nothing - and I only want a single carriage return. Additionally, it seems like type must be markdown. I can also see that the carriage returns are correctly injected as well:

>>> [{'shop': {'value': '3000 Mall View Road\n Suite 1107 Bakersfield\n CA 93306', 'type': 'markdown'}, 'sales': {'value': 'Sales were **7 less** than the goal', 'type': 'markdown'}, 'goal': 'Goal was not achieved'}, {'shop': {'value': '2130 Center Street\n Suite 102 Berkeley\n CA 94704', 'type': 'markdown'}, 'sales': {'value': 'Sales were **0 more** than the goal', 'type': 'markdown'}, 'goal': 'Goal was achieved'}, {'shop': {'value': '652 Pine Knot Avenue Big Bear Lake\n CA 92315', 'type': 'markdown'}, 'sales': {'value': 'Sales were **1 more** than the goal', 'type': 'markdown'}, 'goal': 'Goal was achieved'}]

@AnnMarieW Got it - you need both 2 spaces AND the carriage return: <sp><sp>\n:

        tip['shop']['value'] = tip['shop']['value'].replace(",", "  \n")
1 Like

Giving up on repositioning - tried to make the changes in the src files then build it as a wheel but somehow everything just got destroyed