Flow: <a href="#anchor"> does not link to <a name="anchor> in same page

Created on 3 Feb 2017  路  13Comments  路  Source: vaadin/flow

Normally, when I create <a href="#anchor"> in an HTML page, this will cause there to be link pointing to <a name="anchor"> in that same page. So, for example, if you're on https://localhost:8080/my-page, then clicking the link will take you to https://localhost:8080/my-page/#anchor.

However, in ~Hummingbird~ (now known as Flow), when you create <a href="#anchor"> on https://localhost:8080/my-page, clicking the link will take you to the root of the site instead, to https://localhost:8080/#anchor. This is not expected behavior.

Please make it behave like on a normal site.

enhancement routing

Most helpful comment

I feel that mixing Flow navigation in here is overkill. Developers are looking a quick way to let users navigate within the current page/view.

Code like this should work just like it works in browsers (without any Flow navigation/events happening):

Link link = new Link("View feedback","#feedback");
myView.add(link); 

All 13 comments

This happens because there's a <base href="[site root]"> on the page. It affects how all relative URLs are resolved, including URLs like #anchor.

Which is better?

  • All relative URLs on the page are resolved relative to that page. This means that all resources that are used on multiple pages would have to be defined using absolute URLs.
  • All relative URLs on the page are resolved relative to the root of the site. This means that instead of #anchor, you'd need to write my-page#anchor.

I just did a quick search in our HTML files for "

Where does this <base> tag come from and how do I change it?

Also, if I need to write my-page#anchor, but I do not know what page I'm on (because I'm in a dynamically populated template that is used on multiple pages), how do I find out the correct value for my-page?

The <base> tag is added by the framework, row 336 in BootstrapHandler.java. Removing it would probably break framework internals that are currently implemented based on the assumption that relative URLs are relative to the site root.

Assuming we keep it there in the future as well, it would indeed be good to provide some built-in feature for getting the URL of the current page.

Right not it can be handled manually by populating the template model from the server with UI.getInternal().getActiveViewLocation() or through JS with something like <a [href.attr]="window.location.pathname + '#anchor'">.

So to clarify, you can either create navigation links as href="my/page" or you can create anchor links using href="#anchor". With the current approach, you do not have to include ../ or / before the page/navigation link but do have to include the page link in anchor hrefs.

So to clarify

It's not only about navigation links, it also affects anything else that is referenced by URLs, e.g. stylesheets, scripts and HTML imports.

Right now #anchor links do not work in Flow-managed pages. I do not think this is acceptable:

  • this includes both the links that the developers create themselves and the links that are created by third-party web components

    • while it is theoretically possible to force all Flow developers to change their way of creating #anchor links, it is not possible to do that with third-party web components

Supporting navigation links is a valid use case but there are ways to implement it without introducing the <base> tag (that is, without breaking #anchor links).

Please consider custom URL resolution logic for links with the router-link attribute. They are anyway handled differently (do not trigger a page reload), so they do not have to follow the <base> URL. In this scenario there would be no <base> URL on the page (unless the developer explicitly adds it), #anchor links would keep working as they always have been, and in-app links would work as well since they would implicitly resolve relative to the application root regardless of the current page route.

Internal navigation links should also work e.g. when opening the link in a new tab, so custom logic in the internal navigation handling wouldn't be enough for that case either. We would instead have to do custom URL resolving for the RouterLink component and require that anyone creating their own custom anchor elements with router-link e.g. from a template would manually resolve any URLs they put there.

<base> is also used for other dependencies, so that you can use e.g. @HtmlImport("foo/bar.html") regardless of from which route the annotated component is used (although it's still recommended to use e.g. frontend://foo/bar.html or context://foo/bar.html that would work in either case)

I see two main aspects of using <base> in our tests at least:

  • Resources imports in the <head> tag. We are defining resources like JS, HTML imports, CSS with relative URLs
  • relative paths in router links.

So the first item introduce an issue when a view should handle all URIs which starts with view URI.
E.g. view URI is: http://localhost/path/MyView.
In our tests the same view handles any URI like http://localhost/path/MyView/a/b/c/....
For such URIs properly set <base href> allows to handle relative URIs correctly.
So e.g. link to webcomponents-loader.js resolves correctly in any case.
Without <base href> it doesn't resolve so we cannot proceed at all since we need polyfill.

The second issue is also related to handling different URIs by the same view.
If the view URI is: http://localhost/path/MyView and there is router link to
http://localhost/path/MyView/x/y which is handled by the same view then this link also presents in this view with the same relative URI.
But view now has a different URI ( http://localhost/path/MyView/x/y now , was http://localhost/path/MyView).
It means that now (without <base href>) this router-link will be resolved to a different URI than the same router-link in the original view with original URI.

So <base href> allows to use router links with consistent behavior regardless of view URI.
Without this one has to care about view URI somehow.

Also worth to mention that in our tests there are many places where HistoryStateChangeHandler is replaced to a custom one.
And they works in some unexpected way without having <base href
E.g. RouterLinkUI defines a custom HistoryStateChangeHandler which allows to stay on the same view for all relative router links.
So there is a relative router link "foo" which resolves to http://localhost/run/foo and there is no any view mapped to this URI (not RouterLinkUI view).
Such HistoryStateChangeHandler allows to handle this URI in the same view.
But this URI won't work if page is reloaded.
So I would say this is incorrect usage.

However the API of HistoryStateChangeHandler should also be taken into account in regard to <base href question: the HistoryStateChangeEvent that it receives will contain some another data than having <base href as now.

I feel that mixing Flow navigation in here is overkill. Developers are looking a quick way to let users navigate within the current page/view.

Code like this should work just like it works in browsers (without any Flow navigation/events happening):

Link link = new Link("View feedback","#feedback");
myView.add(link); 

Yes, it should be easy to create inside-page hash-based links from that just work, either in a template or from Java.

No timeline for this enhancement currently though, would require some +1s

I follow the issue as it is creating problem to our application

Following the issue as well, as it renders my current project basically unusable.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pleku picture pleku  路  4Comments

Artur- picture Artur-  路  4Comments

TatuLund picture TatuLund  路  3Comments

pleku picture pleku  路  4Comments

mstahv picture mstahv  路  3Comments