Learn Feedback classes

Unpoly adds CSS classes to links and forms that are loading content, and to the fragments they are targeting. The classes have no effect on their own. They exist so you can style them, to instantly signal that the app is working.

We have a link targeting a fragment #target:

<a href="/path" up-target="#target">Link</a>

<div id="target">
  Initial content
</div>

When the user clicks the link, the link is instantly assigned the .up-active class. The targeted fragment (the #target element) gets the .up-loading class:

<a href="/path" up-target="#target" class="up-active">Link</a> <!-- mark: class="up-active" -->

<div id="target" class="up-loading"> <!-- mark: class="up-loading" -->
  Initial content
</div>

Both classes are removed when the request ends.

Feedback when submitting forms

We have a form targeting a fragment #target:

<form action="/action" up-target="#target">
  <input type="text" name="email">
  <button type="submit">Submit</button>
</form>

<div id="target">
  Initial content
</div>

When the user clicks the submit button, both the button and the form are marked as .up-active while the form is submitting. The targeted fragment is marked as .up-loading:

<form action="/action" up-target="#target" class="up-active"> <!-- mark: class="up-active" -->
  <input type="text" name="email">
  <button type="submit" class="up-active">Submit</button> <!-- mark: class="up-active" -->
</form>

<div id="target" class="up-loading"> <!-- mark: class="up-loading" -->
  Initial content
</div>

Tip

To also prevent the user from interacting with the form while it submits, see Disabling forms while working.

Fields can be active origins

Sometimes a form is not submitted by pressing a submit button, but by interacting with an input field:

  • The user submits by pressing Return inside a focused field.
  • A field with [up-autosubmit] is changed.

In these cases, that field is considered the origin element that caused the submission. It is also marked as .up-active, in addition to the form and its default submit button:

<form action="/action" up-submit class="up-active"> <!-- mark: up-active -->
  <input type="text" name="email" class="up-active"> <!-- mark: up-active -->
  <button type="submit" class="up-active">Submit</button> <!-- mark: up-active -->
</form>

Conveying feedback with CSS styles

To instantly signal that a user interaction has been registered, consider highlighting active links and submit buttons in your CSS:

.up-active:is(a, [up-follow], input[type=submit], button[type=submit], button:not([type])) {
  outline: 2px solid blue;
}

To convey which parts of the page have a pending update, consider styling targeted fragments:

.up-loading {
  opacity: 0.6;
}

You can show a hidden loading message while a form is submitting:

.spinner {
  display: none;

  form.up-active & {
    display: block;
  }
}

If CSS alone is not enough, previews let you make arbitrary changes to the page while a request is loading. See Loading state for all strategies.

Classes are removed when the request ends

Feedback classes remain set while the request is loading. Once the response is received, the .up-active and .up-loading classes are removed:

<a href="/path" up-target="#target">Link</a>

<div id="target">
  New content from server
</div>

Feedback classes are also removed if the request ends for any other reason, such as the server rendering an error code or the request being aborted. See How previews end for all reasons that end a request.

Feedback during cache revalidation

When content is rendered from the cache, no .up-active or .up-loading classes are set, since there is nothing to wait for.

When the cache entry is stale, Unpoly automatically reloads the fragment. During this cache revalidation Unpoly marks the targeted fragment as .up-revalidating instead of .up-loading:

<div id="target" class="up-revalidating"> <!-- mark: class="up-revalidating" -->
  Possibly stale content
</div>

Feedback classes from JavaScript

When rendering from JavaScript, Unpoly sets .up-active on the origin element that caused the interaction. For example, when following a link with up.follow(), that link is .up-active while loading:

up.follow(link)

In situations where Unpoly cannot guess the origin, you can pass it as an { origin } option. For example, when a button click causes a render pass, that button should be the origin:

up.on('click', '.my-button', function(event) {
  up.render({ url: '/path', origin: event.target }) // mark: origin
})

Custom feedback classes

To set additional classes on activated origins, push a class name to up.status.config.activeClasses:

up.status.config.activeClasses.push('activated')

To set additional classes on targeted fragments that are loading new content, push a class name to up.status.config.loadingClasses:

up.status.config.loadingClasses.push('fetching')

To set additional classes during cache revalidation, push a class name to up.status.config.revalidatingClasses:

up.status.config.revalidatingClasses.push('checking')

Disabling feedback classes

To disable feedback classes, set an [up-feedback=false] attribute:

<a href="/path" up-follow up-feedback="false">Link</a> <!-- mark: up-feedback="false" -->

From JavaScript you may pass a { feedback: false } option:

up.follow(link, { feedback: false }) // mark: { feedback: false }