# Transitions, focus and windows

Coordinate visual changes across apps, retain focus and move a live app into another window.

This page describes WU Framework `4.0.0`. Read the [Framework 4.0 and CLI 1.2 migration guide](/docs/guides/releases/) before upgrading an existing project.


Also try [Apps in motion](/labs/interaction/): a React editor, Vue inbox, windows and PiP, typed delivery, transitions and keep-alive. The [scenario guide](/docs/guides/interactive-workspace/) explains how to apply it to your application.

<span id="animar-una-actualización"></span>

<span class="section-anchor" id="section-1"></span>

## Animate an update

`wu.transition(mutate, options)` measures elements carrying `data-wu-vt` before and after a change. It returns `ready`, `updateCallbackDone`, `finished`, `skipTransition()` and `mode`. Await `updateCallbackDone` to catch mutation errors: `ready` and `finished` always resolve. The default mode uses FLIP and Web Animations inside Shadow DOM and respects reduced motion.

```js
import { wu } from 'wu-framework';

const root = document.querySelector('#panel');
const item = document.createElement('div');
item.dataset.wuVt = 'product-42';
item.textContent = 'Product 42';
root.append(item);
const transition = wu.transition(() => {
  item.style.transform = 'translateX(80px)';
}, { root, duration: 250 });
await transition.updateCallbackDone;
await transition.finished;
```

Create `#panel` before running the code. In Vue, await `nextTick()` inside the mutation; in Svelte, await `tick()`. For React, `wuReact.createWuViewTransition(React)` and `wuReact.createUseWuTransition(React)` coordinate renderer commits. `mode: "native-document"` is explicit opt-in; it does not promise to capture every shadow root interior.

`wu.transition.between(fromApp, toApp, key, mutate?, options?)` animates an element across apps using the same `data-wu-vt` key. It accepts `null` for the shell, `fromRoot`/`toRoot`, `duration`, `timeout`, `easing`, `fade` and `ghost`. It returns the same promise contract; a visual animation does not transfer business state.

<span id="foco-accesible-y-keep-alive"></span>

<span class="section-anchor" id="section-2"></span>

## Accessible focus and keep-alive

`wu.focus.remember(name, root)` records deep focus and `restore(name)` restores it; both return a boolean. `forget(name)` releases the record. `trap(root, { initial, restore })` returns a cleanup function for a dialog. `describe(element, { labelledBy, describedBy })` connects labels across roots and returns the applied mode: element references, IDs or text; the last is a snapshot to refresh when its label changes.

Hiding a `keepAlive` app retains its instance. Adapters detect React Activity, Vue scope pausing and Angular view detach/attach when those APIs exist. This does not automatically stop your intervals, sockets or requests: use `wu:app:deactivated` and `wu:app:activated` to pause and resume them, and remove listeners on unmount.

<span id="mover-una-app-viva-a-otra-ventana"></span>

<span class="section-anchor" id="section-3"></span>

## Move a live app to another window

```js
import { wu } from 'wu-framework/core';
import 'wu-framework/windows';

// Run after the host has mounted the editor app.
document.querySelector('#detach-editor').addEventListener('click', async () => {
  try {
    const mode = 'documentPictureInPicture' in window ? 'pip' : 'popup';
    await wu.detach('editor', { window: mode, width: 900, height: 700 });
  } catch (error) {
    document.querySelector('#window-status').textContent = error.message;
  }
});
document.querySelector('#attach-editor').addEventListener('click', () => {
  wu.attach('editor');
});
```

Create the buttons and `#window-status` in the shell. `detach()` requires a mounted, visible app and a user gesture to open the window. It adopts the same DOM nodes; code continues executing in the original window. Use `ownerDocument.defaultView` to inspect the visual window. It accepts a popup, Picture-in-Picture when available or a same-origin `Window`.

`isDetached(name)` reads the state; `windowOf(name)` returns `Window | null`; `windowsReady()` loads the subsystem. Closing the window, hiding or unmounting the app returns it to the host. Handle `WU_APP_NOT_MOUNTED`, `WU_APP_HIDDEN`, `WU_WINDOW_UNAVAILABLE`, `WU_WINDOW_DENIED` and `WU_DETACH_ABORTED`. Listen for `wu:app:detached` and `wu:app:attached` on the container when the renderer needs to react.