vaadin / flow

Vaadin Flow is a Java framework binding Vaadin web components to Java. This is part of Vaadin 10+.
Apache License 2.0
620 stars 167 forks source link

IFrame does not scroll if src includes an id anchor tag (/view#id) #20206

Open drewharvey opened 1 month ago

drewharvey commented 1 month ago

Description of the bug

When a src is set that contains an anchor tag, such as "#some_id", the iframe will not scroll to that element after being loaded.

Expected behavior

As in a normal html iframe element, the contents of the iframe should automatically scroll to the element id listed in the src's anchor tag.

Minimal reproducible example

var iframe = new IFrame();
var btn = new Button("Click Me", e-> iframe.setSrc("/my-view#my-element"));
add(iframe, btn);
@Route("/my-view")
public class IFrameContentsView extends VerticalLayout {
    public IFrameContentsView() {
        // long paragraph so it actually takes some height
        var text = new Span(" Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
                "Pellentesque molestie ultricies lectus ac rhoncus. Quisque auctor venenatis metus," +
                " et tincidunt elit scelerisque in. Donec a magna eget arcu euismod iaculis. Integer " +
                "eget finibus turpis, sed faucibus ligula. Aliquam sed sodales ligula. Aliquam erat volutpa" +
                "t. In sed aliquam elit. Orci varius natoque penatibus et magnis dis parturient montes, nasc" +
                "etur ridiculus mus. Donec tincidunt est aliquet ullamcorper mollis. Integer id sem eu libero " +
                "euismod facilisis nec id turpis. Nullam ullamcorper feugiat fringilla. Nullam ultricies volutpat d" +
                "ui, eu varius dui condimentum eu. Curabitur in lectus faucibus, pellentesque risus et, semper dui.");
        text.addClassName(LumoUtility.FontSize.XXLARGE);
        var scrollElement = new Span("Element to scroll to");
        scrollElement.setId("my-element");
        add(text, scrollElement);
    }
}

Versions

mcollovati commented 1 month ago

The issue can also be reproduced without an IFRAME. I suppose the problem is that when the page is loaded, the element with the anchor is not yet on the DOM, so scrolling does not work automatically. A workaround could be to register a JS execution to the page containing the element

UI.getCurrent().getElement().executeJs("""
        setTimeout(() => {
            $0.scrollIntoView();
        }, 0);
        """, scrollElement);

If the anchor cannot be fixed at compile time, the anchor can be read from the location object, something like

UI.getCurrent().getElement().executeJs("""
        setTimeout(() => {
            const el = document.location.hash && document.getElementById(document.location.hash.replace("#",""));
            if (el) {
                el.scrollIntoView();
            }
        }, 0);
        """);
drewharvey commented 1 month ago

@mcollovati I'm assuming you're saying that even just navigating to a page with an anchor tag does not work? For example, this does not scroll to the correct element. The


// from somewhere (click this in ui)
var a = new Anchor("/home#span80", "Navigate To");
add(a);

// home view
@Route(value = "home")
public class HomeView extends VerticalLayout {

    public HomeView() {
        IntStream.range(0, 100).forEach(i -> {
            var span = new Span(i + "");
            span.setId("span"+i);
            add(span);
        });
    }

}
mcollovati commented 1 month ago

@drewharvey exactly. I think the snippet I posted above should be automatically executed by Flow client once the page is loaded.

mcollovati commented 1 month ago

Actually, the anchor might work, since it should be intercepted by the router and should not reload the page, but I'm not sure the hash is handled. For sure, you open the browser and go to http://host:port/home#span80 the page will not scroll