Open kjacobson opened 4 years ago
Firstly, thank you for your well-argued issue. :)
I think there are a few ways this could be achieved.
FormData
as you suggest, or with a fetch Request
which can include a POST body.Request
could be supplied to create a portal that must immediately navigate.navigate
event that would let you initiate the form submission normally, and send the in-flight navigation request into an (ephemeral as in #192) <portal>
element.As for whether it should be limited to same-site form actions, I'd have to look at how form submission is controlled and whether we want same-origin (or same-site) restrictions in addition to the usual XSRF protections that are the classic if awkward solution.
Another point in favour of this, of course, is that forms can currently target the main frame and iframe (<form target=...>
) and this capability would be missing from portals.
I think this is a reasonable enhancement that could eventually be explored, but I'm less certain that it's necessary to include in an initial/minimal version of this feature, especially since workarounds are available if inconvenient (e.g. using fetch
to do a post in advance of loading the document via a GET, or first loading a stub document that receives a message and does a form submission within the portal). But I do agree that it is unnecessarily duplicative of logic that the UA already has well in hand.
(The request approach runs into the fact that it's currently illegal to construct a Request
whose mode is "navigate"
, though it's conceptually the best existing class to map to the concept of "an arbitrary navigation request, be it GET, POST, etc".)
We'd either end up accepting Request
objects and thoroughly vetting them, or introduce some new kind of API.
We don't want to create a type of navigation that can't already happen, so we'd be restricting the content type to text/plain
, application/x-www-form-urlencoded
, or form/multipart
, and restricting the method to GET
or POST
.
Given the restrictions, I'm leaning towards a new API.
portal.navigate(url, {
method, // GET or POST, defaults to GET.
body, // Optional. Either a FormData object, or a URLSearchParams object.
});
As with the Request
constructor, FormData
would set the content type to form/multipart
, and URLSearchParams
would set the content type to application/x-www-form-urlencoded
. We'd lose text/plain
, but is that really a problem?
createPortalForNavigation
could have the same signature.
One of the major complicating factors in the iframes spec and implementation architecture is how it allows navigating to various non-HTTP(S) URLs, such as data:
, blob:
, javascript:
, about:blank
, as well as the srcdoc=""
feature. I am hopeful we can find a way to achieve the use cases mentioned in this issue without introducing a way for portals to navigate things that are not backed by a HTTP(S) URL.
Thanks for the responses. Right, I suppose that, so long as it's possible to create a JS-abetted workaround, a webapp author can maintain continuity of UX, and that's enough for a first go. What I'm thinking one doesn't want is an MPA where link clicks have slick portal transitions and form submissions give you a flash-of-blank experience.
Jake's suggestion seems like pretty good ergonomics to me:
document.getElementById('myForm').addEventListener('submit', (e) => {
e.preventDefault()
const portal = document.createElement('portal')
portal.navigate(e.target.action, {
method: e.target.method,
body: new FormData(e.target)
})
})
I had forgotten about form targets though:
Another point in favour of this, of course, is that forms can currently target the main frame and iframe (
<form target=...>
) and this capability would be missing from portals.
That seems like a maximal solution in the sense of letting the developer rely on as much native user agent behavior as possible.
Premises
Thesis To further advance this work, I think it's crucial to be able to provide similar transition behavior when the loading and rendering of a new HTML document comes as the result of a form submission, rather than a link click.
A functioning server-rendered web application will have to be able to handle HTTP requests with multipart form-data encoding and respond with new HTML documents, e.g.:
These experiences won't get the transition advantage portals provide without writing a bunch of JavaScript to do things the browser does natively. Again:
So it's not that there is no way whatsoever in the current spec to animate the appearance of a portal which displays the HTML document provided by the server as the response body of a form submission HTTP request. It's that to do so given the current spec would require writing a lot of JS to do things the browser is already pretty good at doing.
It is true that there's no way to get the preload behavior, as form submissions require user input and are not therefore primed for a static request.
Possible solutions (for discussion at least) You currently can set portal src programmatically:
portal.src = 'https://en.wikipedia.org/wiki/World_Wide_Web'
Portals could support programmatically setting
action
(instead ofsrc
) to a URL and settingformData
to aFormData
object and handling submission from there. This still means we have to write some JS to serialize the form, butnew FormData(document.getElementById('myForm'))
is not bad.Alternately, you could be able to reference a form element directly from the portal with a
for
attribute (like thelabel
HTML element has). Basically, portals for forms and portals for links.<form-portal for="myForm">
It seems this should probably be limited to same-site form actions.