The library never decides how long undo stays available. You ask for a node to be kept, and you decide when to let it go.
Keep a removed node
const operation = effects.remove(element, {
retain: true,
});
await operation.finished;
const id = operation.removalId;
With retain: true, the detached original is stored in an internal Map under an opaque RemovalId. It is not moved to a hidden DOM container or DocumentFragment.
Take and restore
take(id) returns the node and removes its strong reference from storage in one operation.
if (id) {
const retained = effects.take(id);
if (retained) {
destination.append(retained);
effects.restore(retained);
}
}
The application chooses append, prepend, before, or any framework-specific insertion method. The library measures the resulting final geometry.
Release references without restoring
effects.discard(removalId); // true when an entry existed
effects.discardAll(); // number of released entries
destroy() also releases all retained nodes.
Avoid accidental memory growth
There is no TTL and no cap on the number of entries. Nothing gets deleted behind your back โ but nothing gets cleaned up for you either. Every RemovalId you do not use has to end up in take(), discard(), or discardAll().
Undo expires when the application decides it does: as a toast closes, on a route change, once a history entry is committed.
Remove permanently
Without retain the removal is already permanent as far as the library is concerned:
effects.remove(element); // retain: false
After completion, neither the operation handle nor the library storage keeps the element alive.