WICG / navigation-api

The new navigation API provides a new interface for navigations and session history, with a focus on single-page application navigations.
https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-api
487 stars 26 forks source link

Event property to access the element who triggered a navigation #225

Open rik opened 2 years ago

rik commented 2 years ago

I think this new API could be very interesting for a library like Hotwire Turbo. The Turbo Frame concept would need to know if the navigation was triggered by an element or not and if that element was configured to do a Turbo navigation or not. As far as I can tell, this information is not available at the moment.

(cc @seanpdoyle from the Turbo community)

domenic commented 2 years ago

That seems like a pretty reasonable addition. This information is similar to event.userInitiated and it would just be a matter of hooking up the actual element instead of making it just a boolean.

Any thumbs-up on the issue from community members would be appreciated, to weigh this versus other additions.

rik commented 2 years ago

Other libraries in the same space that might be interested by this new API and/or this issue: htmx (cc @benpate) and Unpoly (cc @triskweline).

benpate commented 2 years ago

Other libraries in the same space that might be interested by this new API and/or this issue: htmx (cc @benpate) and Unpoly (cc @triskweline).

What is the current status of this API? From this page, it seems like a proposal that hasn't yet been implemented by W3C or major browsers. It certainly looks interesting, and I'll keep an eye on it as it develops!

Also -- thanks for the mention! @1cg is the rockstar behind htmx. I'm just a groupie with a pair of drumsticks :)

domenic commented 2 years ago

What is the current status of this API? From this page, it seems like a proposal that hasn't yet been implemented by W3C or major browsers.

We are preparing to ship this in Chromium, after having run an origin trial for a while. You can find out some details on other browsers' engagement on that link. The W3C does not implement APIs so I don't know what you mean by that.

triskweline commented 2 years ago

Thanks for the mention @rik.

Confirming that this would be relevant for Unpoly, as we're trying to update a minimal fragment around the triggering element (link, submit button) that causes a navigation.

In Unpoly the triggering element is called { origin }, but since you're already using { destination } it wouldn't work well here.

VicGUTT commented 2 years ago

For a use case of where having the element triggering the navigation event would be needed checkout the duplicate issue I previously created: https://github.com/WICG/navigation-api/issues/238 .

tl;dr code

function visit(params) {
    // ...

    navigation.addEventListener('navigate', (e) => {
        const element = e.targetElement; // <- Element or null

        if (!element || !element.hasAttribute('data-visit')) {
            return;
        }

        e.transitionWhile(
            fetch({
                url: element.getAttribute('data-visit-url') || determineUrlToUseFromElement(element),
                method: element.getAttribute('data-visit-method') || determineMethodToUseFromElement(element),
                // ...
            })
            .then(response => response.text())
            .then(html => swapDom(html))
        );
    });
}
natechapin commented 1 year ago

I prototyped this yesterday.

A few design questions that came up:

tbondwilkinson commented 1 year ago
  1. initiatingElement since this is a type of userInitiated? Just thinking about other precedents, when you have an event, the triggering element is event.target, but I don't think target is a clear word here.
  2. I think the use cases for this are typically not cross-document, and so it would be better to leave this same-document.
  3. I think that's okay. What other options could you imagine besides the <form>?
natechapin commented 1 year ago
  1. initiatingElement since this is a type of userInitiated? Just thinking about other precedents, when you have an event, the triggering element is event.target, but I don't think target is a clear word here.

It is often-but-not-always user initiataed, fwiw. At least the way I prototyped it, a form submission will populate the triggering element, even if it was submitted via form.submit() without any user action.

I agree that target isn't really the right word here. initiatingElement is clear, but longer than I was hoping for.

  1. I think the use cases for this are typically not cross-document, and so it would be better to leave this same-document.

Just to clarify: This will be available for cross-document navigations, but not cross-window initiation. <a href="some-other-document.html> will populate the triggering element, but <a href="some-other-document.html target="myIframe"> will not

  1. I think that's okay. What other options could you imagine besides the <form>?

The submitting <input>, if one exists? Idk.

rik commented 1 year ago

In my prototype, when submitting a form, the triggering element is the <form>. Is that ok?

I think it should be the SubmitEvent.submitter. Turbo checks a data-turbo attribute on the submitter to decide wether or not to intercept the navigation.

<form>
    <button type="submit">Intercepts the submission</button>
    <button type="submit" data-turbo="false">Let the browser navigate as usual</button>
</form>
tbondwilkinson commented 1 year ago

Oh and I suppose link.click() would also trigger it.

Just some options: triggering activating originating initiating

I don't have strong opinions I think most of these would be clear.

Ack with cross-window initiation, that was my understanding as well.

+1 to submitter, that does seem useful, especially if there are multiple ways of submitting. If you call form.submit() would you expect the element to be form?

rik commented 1 year ago

If you call form.submit() would you expect the element to be form?

Yes. Same if you call form.requestSubmit().

domenic commented 1 year ago

Trying to settle on the final naming:

Thoughts welcome. This is a pretty simple addition so let's nail down the name soon.

annevk commented 1 year ago

Some thoughts:

domenic commented 1 year ago
  • Should this return something useful when it's not an element?

My instinct is no. Between this and userInitiated and navigationType, I think you should have the information you need. E.g.:

The only extra thing we could consider giving you is the ability to know exactly which API method was used, e.g. location.reload() vs. navigation.reload(), or history.go(-1) vs. history.back(). I don't think that should be necessary?

  • What elements do you get to know about? Same-document only, same-origin within same top-level navigable only (though what about A -> B -> A), something else?

Great point. I think Nate implemented a same-document restriction, but forgot to mention that in https://github.com/WICG/navigation-api/pull/264. That seems like the right conservative starting point. Although I guess it kind of belies my above breakdown; if a cross-document <a> or <form> navigates you, you'll get incorrect results from those kind of boolean expressions. Hmm.

  • Speaking of, could this partially replace sourceDocument?

Yes. We haven't written the spec yet, but I think the way to do things will be to convert sourceDocument into sourceNode, extract out sourceDocument (always non-null) and sourceElement (sometimes non-null) from it early in the navigate algorithm, and pass sourceDocument on to the rest of the algorithm while passing sourceElement on to the specific parts concerned with firing the navigate event.

tbondwilkinson commented 1 year ago

Fine with sourceElement.

Re: booleans, I suppose you would have to check e.sameDocument as well.

bathos commented 1 year ago

I also think sourceElement is clearest among those listed.

rik commented 1 year ago

I'm not seeing this in the merged version within the HTML spec. Are there any blockers to do so?

domenic commented 1 year ago

Nope, @natechapin is working on it :)

rd3k commented 1 year ago

I can see that this has been "Implemented behind the NavigateEventSourceElement flag" in Chromium

How do we enable that flag to try it out? Under what circumstances would it be un-flagged?

rik commented 12 months ago

To give it a try, launch Chrome with this extra argument: --enable-blink-features=NavigateEventSourceElement.

ryantownsend commented 6 months ago

Is there any movement on when this will be unflagged in Blink? Also, do we know whether sourceElement is being included in the other browsers alongside their new Navigation API implementations?

It's immensely useful to be able to toggle an aria-busy on form submission (and use this for user feedback) without having to add additional submit event listeners.

It's hard to understand the status on https://github.com/w3ctag/design-reviews/issues/867 – for clarity: was this closed because TAG don't need to review and therefore it's just automatically accepted as an addition?

domenic commented 6 months ago

I apologize for the lack of progress in shipping sourceElement. It fell through the cracks in a bit of a team transition. I'll try to bump shipping it higher on the priority queue.

bramus commented 6 months ago

This would be very helpful for View Transitions, so that one can capture the correct element – by adding a view-transition-name to it – from within the pageswap event.

ryantownsend commented 5 months ago

Sorry to bump this again, but with the unflagged release of Cross Document View Transitions in Chrome 126, this really needs releasing for the exact use-case that @bramus outlined.