---
name: "up:fragment:loaded"
area: "API"
kind: "DOM event"
parent: "up.fragment module"
url: "https://unpoly.com/api/up:fragment:loaded"
---
<nav aria-label="Unpoly docs">[All docs](https://unpoly.com/index.md) · [up.fragment module](https://unpoly.com/api/up.fragment.md)</nav>

# up:fragment:loaded

This event is [emitted](https://unpoly.com/api/up.emit.md) after the server response was loaded, but before the HTML is used to [change a fragment](https://unpoly.com/api/up.render.md).

This gives you a chance to inspect the response or DOM state right before a fragment would be inserted. You may then choose to [change render options](#event.renderOptions) or [abort](#event.preventDefault) the render pass to do something else instead.

The event is emitted on the targeted layer. When [opening an overlay](https://unpoly.com/learn/opening-overlays.md), the event is emitted on the parent layer of the new overlay.

<nav aria-label="Guides">

- [Learn: Render lifecycle](https://unpoly.com/learn/render-lifecycle.md)

</nav>

<nav aria-label="Contents">

#### Contents

- [Example: Making a full page load instead](#example-making-a-full-page-load-instead)
- [Example: Changing render options](#changing-render-options)
- [Example: Do something else, then retry](#example-do-something-else-then-retry)
- [Example: Discarding a revalidation response](#example-discarding-a-revalidation-response)
- [Cases that trigger the event](#cases)
- [Event properties](#properties)

</nav>

## Example: Making a full page load instead {#example-making-a-full-page-load-instead}

Event listeners may call `event.preventDefault()` on an `up:fragment:loaded` event to prevent any changes to the DOM and browser history.

This is useful to detect an entirely different page layout (like a maintenance page or fatal server error) which should be opened with a full page load:

```js
up.on('up:fragment:loaded', (event) => {
  let isMaintenancePage = event.response.header('X-Maintenance')

  if (isMaintenancePage) {
    // Prevent the fragment update and don't update browser history
    event.preventDefault()

    // Make a full page load for the same request.
    event.request.loadPage()
  }
})
```

## Example: Changing render options {#changing-render-options}

Instead of preventing the update, listeners may also access the `event.renderOptions` object to mutate options to the [`up.render()`](https://unpoly.com/api/up.render.md) call that will process the server response:

```js
up.on('up:fragment:loaded', async function(event) {
  // If we see an X-Course-Completed header, render the main target
  if (event.response.header('X-Course-Completed')) {
    event.renderOptions.target = ':main'
  }
})
```

## Example: Do something else, then retry {#example-do-something-else-then-retry}

You may retry a prevented fragment update later, by calling [`up.render(event.renderOptions)`](https://unpoly.com/api/up.render.md):

```js
up.on('up:fragment:loaded', async function(event) {
  // When we couldn't access a page since we're signed out, the server sends a header
  if (event.response.header('X-Session-Missing')) {
    // Don't render the error message
    event.preventDefault()

    // Sign in using a modal overlay
    await up.layer.ask({ url: '/sign_in', acceptEvent: 'app:session:created' })

    // Now that we're signed in, retry the original request
    up.render(event.renderOptions)
  }
})
```

## Example: Discarding a revalidation response {#example-discarding-a-revalidation-response}

When rendering [cached](https://unpoly.com/learn/caching.md) content that is too old, Unpoly automatically reloads the fragment to ensure that the user never sees expired content. This process is called [cache revalidation](https://unpoly.com/learn/caching.md#revalidation).

To prevent the insertion of [revalidated](https://unpoly.com/learn/caching.md#revalidation) content _after_ the server responded you may prevent the `up:fragment:loaded` event with an `{ revalidating: true }` property.

The following would skip rendering a revalidation response if it has the same `X-Version` header as the original, stale response:

```js
up.on('up:fragment:loaded', function(event) {
  if (event.revalidating) {
    let newVersion = event.response.header('X-Version')
    let oldVersion = event.expiredResponse.header('X-Version')
    if (newVersion === oldVersion) {
      event.skip()
    }
  }
})
```

Also see [skipping a loaded response](https://unpoly.com/learn/render-lifecycle.md#skipping-responses).

## Cases that trigger the event {#cases}

The `up:fragment:loaded` event is emitted when we have an HTML response from the server _and_ we are about to render elements:

| Case | `up:fragment:loaded` emitted? |
| --- | --- |
| Server responds with 200 OK | ✔️ yes |
| Server responds with an [error code](https://unpoly.com/learn/error-responses.md) | ✔️ yes |
| Rendering from [cache](https://unpoly.com/learn/caching.md) | ✔️ yes |
| Rendering a [string of HTML](https://unpoly.com/learn/providing-html.md#string) | ❌ no |
| Server [renders nothing](https://unpoly.com/learn/conditional-requests.md#rendering-nothing) | ❌ no |
| [Fatal network error](https://unpoly.com/learn/network-issues.md#disconnects) | ❌ no |
| [Preloading](https://unpoly.com/learn/preloading.md) | ❌ no |

---

## Event properties {#properties}

### event.preventDefault() {#event.preventDefault}

(required)

Aborts this render pass without changes.

Programmatic callers will reject with an `up.Aborted` error.

### event.skip() {#event.skip}

(required)

Finishes this render pass without changes, usually to [not re-insert identical content](https://unpoly.com/learn/render-lifecycle.md#skipping-responses).

Programmatic callers will fulfill with an [empty](https://unpoly.com/api/up.RenderResult.prototype.none.md) [`up.RenderResult`](https://unpoly.com/api/up.RenderResult.md).

To configure global rules for responses that should be skipped, you may also use [`up.fragment.config.skipResponse`](https://unpoly.com/api/up.fragment.config.md#config.skipResponse) instead of registering an `up:fragment:loaded` listener.

### event.request {#event.request}

(required)

The original request to the server.

Type: [up.Request](https://unpoly.com/api/up.Request.md)

### event.response {#event.response}

(required)

The response received from the server.

Type: [up.Response](https://unpoly.com/api/up.Response.md)

### event.revalidating (Experimental) {#event.revalidating}

(required)

Whether responding to a [cache revalidation](https://unpoly.com/learn/caching.md#revalidation) request.

Type: boolean

### event.expiredResponse (Experimental) {#event.expiredResponse}

(required)

When [revalidating](https://unpoly.com/learn/caching.md#revalidation), this property is set to the expired content that is being reloaded.

You may compare the `{ response }` and `{ expiredResponse }` properties to prevent [re-insertion of identical content](https://unpoly.com/learn/render-lifecycle.md#skipping-responses).

Also see [`up.fragment.config.skipResponse`](https://unpoly.com/api/up.fragment.config.md#config.skipResponse).

Type: [up.Response](https://unpoly.com/api/up.Response.md) | undefined

### event.origin {#event.origin}

(required)

The link, input or form element that caused the fragment update.

If no origin element is known, this property is left `undefined`.

Type: [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) | undefined

### event.renderOptions {#event.renderOptions}

(required)

Options for the [`up.render()`](https://unpoly.com/api/up.render.md) call that will process the server response.

Listeners may inspect or [modify](#changing-render-options) these options.

Type: [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects)

