A person confirms a dialog. The calling code has its answer, but the dialog may need another fraction of a second to disappear. Removing it immediately cuts off the animation. Waiting for the last frame before returning the answer makes application behavior depend on presentation timing.

I built a headless React library to give those events separate ownership. The library manages the registry, stack and lifecycle. The application supplies the dialog and its appearance.

Answered does not mean removed

Closing resolves the result and starts the exit. Removal follows completion of the exit, with a duration fallback. Hiding is a separate operation that keeps the instance available.

These distinctions matter with stacked dialogs and repeated close actions. An instance can still be visible after its caller has received an answer. It can also remain available while hidden. Treating all of those conditions as open or closed forces callers to reconstruct the missing states.

I put that lifecycle in the library so each application does not have to recreate it around its animations. The caller can await an answer without owning the disappearing component.

The API must preserve the answer's type

Each registered overlay connects its name, input props and result type. A confirmation and a selection dialog can return different answers without making the caller recover their types by hand.

I test public types separately from runtime behavior. A dialog that exits correctly can still expose an API that accepts missing props. Conversely, correct inference says nothing about what a second close call does to an instance already leaving.

What remains with the component

A headless lifecycle manager cannot supply the interaction details of a dialog it does not render. Accessible naming, keyboard behavior and focus restoration remain responsibilities of the supplied interface.

Defining that boundary keeps the library small and makes its guarantees inspectable. The implementation and lifecycle tests are public below.

Public implementation

Repository and API documentation ↗ Exit-lifecycle tests ↗

Working through a reusable component contract?

Describe your case ↗