Skip to content

Add support for clickable hover text or a per pt onclick attribute #998

Open

Description

@etpinard

Users can put links inside hover labels, but when user try to click the link, the hover label obviously disappears. So perhaps we could add optional “sticky” hover labels, where you click and the hover label is persistent until you click again?

Defining what sticky means will be tricky. It probably doesn't apply to every situation. Maybe we could add it as a new layout.hovermode e.g. 'hovermode: 'sticky'.

So, maybe instead we could define a linkonclick attribute e.g. linkonclick: ['https://plot.ly/~empet/101', 'https://plot.ly', /* ... one link per data pt */] that way clicking on a data pt would open the link instead of hovering on the data pt -> move mouse over link in hover label -> click on it.

cc @jackparmer

Activity

  1. john-soklaski commented on Sep 30, 2016

    @john-soklaski

    We definitely would have use for a hover label that the user can interact with. There is quite a bit of information in our hover labels (5-6 lines of text), and users would often like to copy and paste some text from the hover label, or potentially click a link.

  2. jackparmer commented on Sep 30, 2016

    @jackparmer
    Contributor

    @john-soklaski what do you think the right interaction is for allowing a user to select copy paste what is in a hover tag?

  3. john-soklaski commented on Sep 30, 2016

    @john-soklaski

    @jackparmer I think persisting the hover label if a user moves the mouse cursor along the arrow to the hoverlabel makes sense (with hovermode: closest)

  4. maresk commented on Oct 14, 2016

    @maresk

    @jackparmer I will second this feature request in the python API. Our clients would like to be able to interact with content related to a particular data point so ss far as interaction goes, the text should persist, and a hyperlink placed in the text should be clickable.

  5. latorrefabian commented on Dec 8, 2016

    @latorrefabian

    +1

  6. dr-stringfellow commented on Feb 15, 2017

    @dr-stringfellow

    +1

  7. jackparmer commented on Feb 15, 2017

    @jackparmer
    Contributor

    @john-soklaski , @maresk , @latorrefabian , @maierbenedikt - you may be interested in discussion here, Annotations that show & hide on clicking data: #1266

  8. alexcjohnson commented on Feb 15, 2017

    @alexcjohnson
    Collaborator

    And see the implementation of clicktoshow in #1265 - at some point we do intend to implement a way to generate "sticky" annotations programmatically on clicking a data point but for now, as long as you don't have too much data you can do it the other way around: pre-generate all the annotations you might want and link them to appear on clicking the appropriate data points.

  9. slremy commented on May 4, 2017

    @slremy

    Hello all!
    Am I missing something fundamental here? Is there a purpose of being able to have hyperlinks in the text if you can't click them?

    image

  10. alexcjohnson commented on May 4, 2017

    @alexcjohnson
    Collaborator

    Am I missing something fundamental here? Is there a purpose of being able to have hyperlinks in the text if you can't click them?

    We support text in a lot of different contexts, and in most of the other contexts the links are clickable. So it would require special code to disable link creation within the unclickable contexts, and that extra complexity seemed unnecessary since really, is there a purpose to adding hyperlinks that you can't click? 😉

  11. slremy commented on May 5, 2017

    @slremy

    That makes sense!

  12. PaNDanese commented on Jun 3, 2017

    @PaNDanese

    what do you think the right interaction is for allowing a user to select copy paste what is in a hover tag?

    @jackparmer I think clicking on the marker itself would be ideal to toggle the stickiness of the hover tag.

    • Click on the marker and the hover tag persists and you can then copy/paste hover tag-text and click on hyperlinks in the hover tag
    • Click on the marker again and the hover tag "unsticks".

    +1 for utility

  13. wroscoe commented on Jul 7, 2017

    @wroscoe

    +1 for this. This would enable users to dig into the data by linking other related charts. I like the simple solution proposed by @pdanese

  14. 33 remaining items

  15. removed their assignment
    on Aug 2, 2024
  16. plaffitte commented on Aug 5, 2024

    @plaffitte

    +1

  17. npinter commented on Aug 7, 2024

    @npinter

    I managed to find a workaround to make every hoverbox sticky. Just click on the datapoint to make the hoverbox sticky. Remove it by clicking the hoverbox or the datapoint again.

    The trick was to make a copy of the hoverlayer <g></g> tag and move it to a new hoverlayer in the second <svg> object where the axes of the plot are stored. The persistent-hoverlayer is then placed after the <g></g> tag with the shapelayer class.

    I generate the plot in Python and send it via POST to my HTML template. But the code should work for other implementations as well. Add this function inside your <script></script> element:

    function setupPersistentHover(plotDiv) {
        const mainSvgs = plotDiv.querySelectorAll('.main-svg');
        if (mainSvgs.length === 0) {
            console.error("No main SVG elements found in plot");
            return;
        }
    
        const targetSvg = mainSvgs[1];
        const layerAbove = targetSvg.querySelector('.layer-above');
        if (!layerAbove) {
            console.error("Layer-above element not found in plot");
            return;
        }
    
        let persistentHoverLayer = layerAbove.querySelector('.persistent-hoverlayer');
        if (!persistentHoverLayer) {
            persistentHoverLayer = document.createElementNS("http://www.w3.org/2000/svg", "g");
            persistentHoverLayer.classList.add("persistent-hoverlayer");
            const shapelayer = layerAbove.querySelector('.shapelayer');
            if (shapelayer) {
                shapelayer.after(persistentHoverLayer);
            } else {
                layerAbove.appendChild(persistentHoverLayer);
            }
        }
    
        plotDiv.on('plotly_click', function(data) {
            const hoverLayer = plotDiv.getElementsByClassName("hoverlayer")[0];
            if (hoverLayer) {
                const hoverBox = hoverLayer.getElementsByClassName("hovertext")[0];
                if (hoverBox) {
                    const existingHoverBox = Array.from(persistentHoverLayer.children).find(child =>
                        child.textContent === hoverBox.textContent
                    );
    
                    if (existingHoverBox) {
                        existingHoverBox.remove();
                    } else {
                        const persistentHoverBox = hoverBox.cloneNode(true);
                        persistentHoverBox.style.pointerEvents = 'all';
    
                        // generate a unique id for the hover box
                        const hoverBoxId = 'hover-' + Date.now();
                        persistentHoverBox.setAttribute('id', hoverBoxId);
    
                        persistentHoverBox.addEventListener('click', function(e) {
                            e.stopPropagation();
                            this.remove();
                        });
    
                        persistentHoverLayer.appendChild(persistentHoverBox);
                    }
                }
            }
        });
    }
    

    You need to call the function after the plot was generated:

    $('#features_plot').html(data);
    const featurePlotDiv = document.getElementById('features_plot').getElementsByClassName('js-plotly-plot')[0];
    if (featurePlotDiv) {
        setupPersistentHover(featurePlotDiv);
    }
    

    This might not be the best practice solution (and I'm not a webdev ;) ) but it works!

    EDIT:
    added the function to make all hoverboxes sticky

  18. astro-manny commented on Aug 14, 2024

    @astro-manny

    The solution by @npinter works like a charm for my use case. Thank you 🙏❤️
    I use Plotly in Grafana through the ae3e-plotly-panel plugin.

  19. janosh commented on Aug 14, 2024

    @janosh

    has anyone figured out how to do this in python?

  20. philipjames44 commented on Aug 14, 2024

    @philipjames44

    Saw this was closed as completed? Do we have a PR/version we can integrate?

  21. schoukah commented on Dec 16, 2024

    @schoukah

    Saw this was closed as completed? Do we have a PR/version we can integrate?

    Also wondering why this was closed,

  22. dynobo commented on Dec 16, 2024

    @dynobo

    Also wondering why this was closed,

    My best guess is that @gvwilson considered the workaround from this comment as a proper user side "solution".

    In my opinion, the workaround on user side should not be considered as solution of this issue, because

    1. It requires significant implementation on user side. Solving it in plotly itself seems more reasonable and future proof.
    2. This workaround will be very difficult to find (hidden in comment of an issue which was closed without explicitly stating a reason for closing).

    I'd strongly vote for reopening this issue, but the bare minimum would be stating a reason for closing it.

    @gvwilson , could you please comment on this?

  23. dynobo commented on Dec 18, 2024

    @dynobo

    Thanks for reopening! ❤️

  24. kburchfiel commented on Sep 3, 2025

    @kburchfiel

    Yes, thank you! The ability to show tooltips only after clicking on a bar/map region/etc. would be very helpful. For instance, it would be nice to see basic information while hovering and then more detailed information when clicking on an item.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3backlogfeaturesomething new

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions