When two requests target the same element, Unpoly aborts the earlier request. Only the later response is rendered, regardless of the order in which responses arrive. This prevents non-deterministic updates when two requests race to render the same fragment.
By default, a render pass aborts earlier requests targeting fragments within its own targeted fragments. Requests targeting other fragments are not aborted.
To visualize this, consider a layout with a sidebar (#side) and a content area (#main).
Contained within #main is a smaller fragment #box:
The sidebar #side is on the left and the content area #main on the right, side by side.
The smaller #box sits inside #main.
In this layout, rendering has the following effects:
#side and #main do not abort each other.#main, the first request is aborted by the second request.#main aborts an earlier request targeting #box.#box does not abort an earlier request targeting #main.Other work waiting on a fragment stops as well when the fragment is aborted: polling ends, and pending validations are dropped.
To control which requests are aborted, pass an { abort } option to rendering functions
like up.follow(), up.submit() or up.render(). In your HTML, set an [up-abort] attribute with the same values:
<a href="/dashboard" up-follow up-abort="layer">Dashboard</a> <!-- mark: up-abort="layer" -->
| Value | Effect |
|---|---|
'target' |
Aborts earlier requests targeting fragments within your targeted fragments. This is the default. |
'layer' |
Aborts all requests targeting a fragment on the same layer as you. |
'all' |
Aborts all requests targeting any fragment on any layer. |
false |
Aborts nothing. |
With { abort: false }, two requests targeting the same fragment are rendered in the order of their responses.
If the first response removes the fragment targeted by the second request, the second request
fails or updates a fallback target.
To protect a request from being aborted through { abort }, pass an { abortable: false } option
or set an [up-abortable="false"] attribute:
<form method="post" action="/orders" up-submit up-abortable="false"> <!-- mark: up-abortable="false" -->
...
</form>
Submitting this form is not interrupted when the user navigates to another page while the request is loading.
An aborted request may already have reached your server. For a form that changes data, aborting only means that its response is not rendered.
Preload requests are not abortable by default, so navigating does not cancel a menu that is still preloading in the background.
To abort requests targeting a fragment, pass the element or a selector to up.fragment.abort():
up.fragment.abort('.content')
To abort all requests targeting a layer, pass a { layer } option:
up.fragment.abort({ layer: 'root' })
up.fragment.abort({ layer: 'any' }) // aborts requests on all layers
There is also a low-level up.network.abort() function, which aborts requests matching a
URL pattern or an arbitrary condition. Prefer up.fragment.abort() when you can:
only requests aborted by screen region let components react to being aborted.
When requests are aborted through { abort } or up.fragment.abort(), an up:fragment:aborted event
is emitted on the element for which requests were aborted, and an up:request:aborted event for each aborted request.
A rendering function whose request was aborted rejects with an up.Aborted error.
Its { name } is 'AbortError', like the DOMException that fetch() and other native APIs reject with when aborted.
To detect both kinds of aborts, check the error's name:
try {
await up.render({ url: '/path', target: '.content' })
} catch (error) {
if (error.name === 'AbortError') { // mark: error.name === 'AbortError'
console.log('Rendering was aborted: ' + error.message)
}
}
To run code when an element or one of its ancestors in the same layer was aborted, use up.fragment.onAborted().
For example, a timer that reloads an element after 10 seconds should not fire once the element's requests were aborted:
let timeout = setTimeout(() => up.reload(element), 10000)
up.fragment.onAborted(element, () => clearTimeout(timeout)) // mark: up.fragment.onAborted
The callback is unsubscribed automatically when the element is destroyed.
The following rules apply when opening or closing overlays:
{ abort } option used.up.fragment.abort({ layer: 'root' }) keeps the requests, polling and pending validations in an overlay.When a fragment is removed from the DOM with up.destroy(), any request targeting this fragment (or its descendants)
is aborted. This is regardless of the { abort } option used.
A render pass that replaces a fragment also aborts requests targeting the removed elements,
unless it was given { abort: false }.
Tip Your coding agent can search these docs locally with the Unpoly agent skill