---
area: "Learn"
parent: "Advanced rendering chapter"
url: "https://unpoly.com/learn/targeting-fragments"
---
<nav aria-label="Unpoly docs">[All docs](https://unpoly.com/index.md) · [Advanced rendering chapter](https://unpoly.com/learn/advanced-rendering.md)</nav>

# Targeting fragments

A _target_ is a CSS selector that names the fragment to update. Unpoly matches it in both the current page and the server response, then swaps the old element for the new one. A target can also address several fragments, append to a list, or pick the match closest to the link the user clicked.

<nav aria-label="Contents">

#### Contents

- [Swapping a fragment](#swapping)
- [Targeting the main fragment](#targeting-the-main-element)
- [Updating multiple fragments](#multiple)
- [Optional targets](#optional-targets)
- [Appending or prepending children](#appending-or-prepending)
- [Replacing all children](#content)
- [Targeting nothing](#targeting-nothing)
- [Targeting the entire layer](#targeting-the-entire-layer)
- [Resolving ambiguous selectors](#ambiguous-selectors)
- [Dealing with missing targets](#missing-targets)
- [Targeting an element object](#targeting-an-element-object)
- [Changing the target in-flight](#changing-target)

</nav>

## Swapping a fragment {#swapping}

Set an `[up-target]` attribute with a CSS selector on a link or form:

```html
<a href="/posts/5" up-target=".content">Read post</a>

<div class="content">
  Post will appear here
</div>

<div class="other">
  This fragment will not change.
</div>
```

The server response is expected to include an element matching `.content`. The response may include other HTML, even an entire HTML document, but only the element matching `.content` is updated on the page. Other elements from the response are discarded, except [hungry elements](https://unpoly.com/learn/hungry-elements.md).

Many [JavaScript functions](https://unpoly.com/api/up.fragment.md) take a `{ target }` option to indicate what fragment should be updated:

```js
up.render({ target: '.content', url: '/posts/5' })
```

## Targeting the main fragment {#targeting-the-main-element}

Most links and forms update the site's primary content area, called the [main fragment](https://unpoly.com/api/main.md). Omit the target to update it:

```html
<a href="/posts/5" up-follow>Read post</a>

<main>
  Post will appear here
</main>
```

The [`:main`](https://unpoly.com/api/main.md) selector names the main fragment explicitly, which is useful when it is one of multiple targets. Likewise, a JavaScript function that omits its `{ target }` option updates the main fragment:

```js
up.render({ url: '/posts/5' })
```

The main fragment is often, but not always, the HTML `<main>` element. Any element with an [`[up-main]`](https://unpoly.com/api/up-main.md) attribute can be the main fragment, and so can the layer's [topmost swappable element](#targeting-the-entire-layer). The selectors that find it are the _main targets_ in [`up.fragment.config.mainTargets`](https://unpoly.com/api/up.fragment.config.md#config.mainTargets).

## Updating multiple fragments {#multiple}

Separate selectors with a comma to update multiple fragments from a single request. Here opening a post also updates a bubble showing the number of unread posts:

```html
<a href="/posts/5" up-target=".content, .unread-count">Read post</a>
```

When one of your target elements is an ancestor of another target, Unpoly only updates the ancestor. The following link would only update `body`, since that already contains `.unread-count`:

```html
<a href="/home" up-target="body, .unread-count">...</a>
```

## Optional targets {#optional-targets}

By default Unpoly expects all targeted fragments to be present in both the current page and the server response. If a target selector is missing in the current page or in the response, an error `up.CannotMatch` is thrown.

Mark a target as optional with the [`:maybe`](https://unpoly.com/api/maybe.md) pseudo-selector:

```html
<a href="/posts/5" up-target=".content, .unread-count:maybe">Read post</a>
```

Now only `.content` is required to match. If `.unread-count` is missing in the current page or in the server response, Unpoly only updates `.content` without an error.

Instead of listing an optional element in every link's target, you can set an [`[up-hungry]`](https://unpoly.com/api/up-hungry.md) attribute on the element itself. A hungry element is updated whenever a response contains a matching element, regardless of what was targeted:

```html
<div class="unread-count" up-hungry>12</div>

<!-- Following this link will update .content, .unread-count:maybe -->
<a href="/posts/5" up-target=".content">Read post</a>
```

Common use cases for [`[up-hungry]`](https://unpoly.com/api/up-hungry.md) are unread message counters or page-specific subnavigation. Such elements often live in the application layout, outside of the fragment that is being targeted. See [Hungry elements](https://unpoly.com/learn/hungry-elements.md) for details.

## Appending or prepending children {#appending-or-prepending}

Instead of swapping an entire fragment, you can _append_ children to an existing fragment with the `:after` pseudo-selector. In the same fashion, `:before` _prepends_ the loaded content.

A practical example is a paginated list of items. Below the list is a link to load the next page. With `:after` in the `[up-target]`, the next items are appended to the existing list:

```html
<ul class="tasks">
  <li>Wash car</li>
  <li>Purchase supplies</li>
  <li>Fix tent</li>
</ul>

<a href="/tasks?page=2" class="next-page" up-target=".tasks:after, .next-page">
  Load more tasks
</a>
```

The server is still expected to render an entire `<ul class="tasks">`, but only its `<li>` children are used to extend the existing list. The second target, `.next-page`, replaces the link with one pointing to the page after.

## Replacing all children {#content}

To keep the target element, but replace all of its child content, use the `:content` pseudo-selector:

```html
<div class="card">...</div>

<a href="/cards/5" up-target=".card:content">Show card #5</a>
```

The server is still expected to render an element matching `.card`, but only its child content is used. The `.card` element itself keeps its attributes, event listeners and any state your scripts attached to it.

For more advanced strategies for keeping elements, see [Keeping elements](https://unpoly.com/learn/keeping-elements.md).

## Targeting nothing {#targeting-nothing}

To make a server request without changing a fragment, target the [`:none`](https://unpoly.com/api/none.md) selector:

```html
<a href="/ping" up-target=":none">Ping server</a>
```

## Targeting the entire layer {#targeting-the-entire-layer}

To replace all visible elements of a [layer](https://unpoly.com/api/up.layer.md), use the [`:layer`](https://unpoly.com/api/layer.md) selector. It targets the layer's topmost swappable element:

```html
<a href="/admin" up-follow up-target=":layer">Admin area</a>
```

The topmost swappable element is the first child of the layer's container element:

- For the [root layer](https://unpoly.com/api/up.layer.root.md) it is the `<body>` element.
- For an overlay, it is the `{ target }` that the overlay was opened with.
- If an overlay was opened without an explicit target, Unpoly will create a [main fragment](https://unpoly.com/api/up-main.md). This main fragment becomes the topmost swappable target.

## Resolving ambiguous selectors {#ambiguous-selectors}

Sometimes there are multiple components with the same selector on the page:

```html
<div class="card">...</div>
<div class="card">...</div>
<div class="card">...</div>
```

While you can [set `[id]` attributes to uniquely identify an element](https://unpoly.com/learn/target-derivation.md), this is often not necessary. When an ambiguous selector like `.card` matches more than one element, Unpoly prefers to match a fragment near the link or form that the user interacted with (the _origin_). If there is no match in close proximity, Unpoly updates the first match in the [layer](https://unpoly.com/api/up.layer.md).

When rendering programmatically, pass the interaction's origin element as [`{ origin }`](https://unpoly.com/api/up.render.md#options.origin) option.

Below are examples of ambiguous selectors that Unpoly resolves by proximity to the origin. A more elaborate example is the [Tasks list](https://demo.unpoly.com/tasks) of the [Unpoly Demo App](https://demo.unpoly.com/).

### Targeting an ancestor element {#targeting-an-ancestor-element}

Assume we have two links that replace `.card`:

```html
<div class="card">
  Card #1 preview
  <a href="/cards/1" up-target=".card">Show full card #1</a>
</div>

<div class="card">
  Card #2 preview
  <a href="/cards/2" up-target=".card">Show full card #2</a>
</div>
```

When clicking _"Show full card #2"_, Unpoly replaces the _second_ card, since that is a matching ancestor of the followed link.

The origin can only be considered in the current page, not in the server response. In the example above the server is expected to render a single `.card` element.

### Targeting a sibling element {#targeting-a-sibling-element}

```html
<div class="card">
  <div class="card-text">Card #1 preview</div>
  <a href="/cards/1" up-target=".card .card-text">Show full card #1</a>
</div>

<div class="card">
  <div class="card-text">Card #2 preview</div>
  <a href="/cards/2" up-target=".card .card-text">Show full card #2</a>
</div>
```

When clicking _"Show full card #2"_, Unpoly replaces the `.card-text` within the second card.

Again the server is expected to render a single `.card` element, since the origin is only known in the current page.

### Referring to the origin element {#referring-to-the-origin-element}

Instead of relying on proximity, your targets can use [`:origin`](https://unpoly.com/api/origin.md) to refer to the interaction's origin element. The [`:origin`](https://unpoly.com/api/origin.md) placeholder is replaced with a target [derived](https://unpoly.com/learn/target-derivation.md) from the origin element.

Below we see two links that will each update the `<div>` next to them. This requires a rather verbose `[up-target]` attribute:

```html
<a href="/tasks/1" up-target="a[href='/tasks/1'] + div">Show task 1</a>
<div>Task 1 will appear here</div>

<a href="/tasks/2" up-target="a[href='/tasks/2'] + div">Show task 2</a>
<div>Task 2 will appear here</div>
```

We can simplify the `[up-target]` by referencing the followed link as [`:origin`](https://unpoly.com/api/origin.md):

```html
<a href="/tasks/1" up-target=":origin + div">Show task 1</a>
<div>Task 1 will appear here</div>

<a href="/tasks/2" up-target=":origin + div">Show task 2</a>
<div>Task 2 will appear here</div>
```

When a link is clicked, [`:origin`](https://unpoly.com/api/origin.md) is replaced with a target [derived](https://unpoly.com/learn/target-derivation.md) from the link element. For example, clicking on the second link will target `a[href='/tasks/2']`.

### Disabling region-aware fragment matching {#disabling-region-aware-fragment-matching}

If matching fragments around the origin does not work for you, you can tell Unpoly to always use the first fragment matching the target selector:

- Pass a `{ match: 'first' }` option to a function that matches a fragment.
- Set an `[up-match=first]` attribute on a link or form.
- Configure `up.fragment.config.match = 'first'` to disable region-aware matching for all functions and elements. You can then opt in again with `{ match: 'region' }` or `[up-match=region]`.

## Dealing with missing targets {#missing-targets}

By default Unpoly requires targets to match in both the current page and the server response. If no matching element is found in the current page or in the response, an error `up.CannotMatch` is thrown.

For individual fragments that may be missing, [make the target optional](#optional-targets) with [`:maybe`](https://unpoly.com/api/maybe.md). When the _primary_ target may be missing, configure a fallback instead.

### Providing a fallback target {#providing-a-fallback-target}

A _fallback target_ is used when the primary target cannot be matched. Pass it as an `[up-fallback]` attribute or `{ fallback }` option:

```js
up.render({ url: '/path', target: '.content', fallback: 'body' })
```

If `.content` is missing in the current page or in the response, Unpoly updates the `body` element.

If neither the primary nor the fallback target can be matched, the render pass fails with an error `up.CannotMatch`.

### Falling back to the main target {#falling-back-to-the-main-target}

It is often useful to render the [main target](https://unpoly.com/api/main.md) when the primary target cannot be matched. Missing targets are often caused by the server rendering an error message, or an unexpected screen like a login form. Falling back to the main target shows that screen, instead of the link or form failing silently.

To fall back to the main target, set an empty `[up-fallback]` attribute or pass a `{ fallback: true }` option:

```js
up.render({ url: '/path', target: '.content', fallback: true })
```

Falling back to the main target is the default when [navigating](https://unpoly.com/learn/navigation-defaults.md). Links and forms navigate by default, so they don't need an `[up-fallback]` attribute.

## Targeting an element object {#targeting-an-element-object}

When you pass an [`Element`](https://developer.mozilla.org/en-US/docs/Web/API/Element) object to a rendering function, Unpoly [derives](https://unpoly.com/learn/target-derivation.md) a selector that matches the element:

```js
let element = document.querySelector('#foo')

up.reload(element) // Derives the target '#foo' from the given element
```

The element is also used as the [origin](#ambiguous-selectors) of the update. See [Target derivation](https://unpoly.com/learn/target-derivation.md) for details and examples.

## Changing the target in-flight {#changing-target}

The server may elect to render a different target by setting an [`X-Up-Target`](https://unpoly.com/api/X-Up-Target.md) response header.

Events like [`up:link:follow`](https://unpoly.com/api/up:link:follow.md), [`up:form:submit`](https://unpoly.com/api/up:form:submit.md) and [`up:fragment:loaded`](https://unpoly.com/api/up:fragment:loaded.md) also let you change the target by setting `event.renderOptions.target` to a new selector. See [Changing options before rendering](https://unpoly.com/learn/render-lifecycle.md#changing-options-before-rendering) for an example.

<nav aria-label="Reading order">

- [Previous: Navigation defaults](https://unpoly.com/learn/navigation-defaults.md)
- [Next: Target derivation](https://unpoly.com/learn/target-derivation.md)

</nav>

