Solution: Ghost Overlays

Ghost Overlays use separate, distinct view components to render either the real DOM or the ghost DOM.

Ghost List is an overlay DOM group

This approach provides maximum features to animate DOM during :enter and :leave events, to stagger elements… all independent of the other layer. This approach also provides a ‘separation of concerns’: the real-DOM is neither aware of nor impacted by Ghost DOM.

Note: if exact positioning is needed, proper layout of Ghost Overlays can be challenging.

With ghost overlays, we can create totally separate components and control the quantity of ghosts, locations, and animations very easily. In the code below, our overlay is the <ghost-list> component.

Here is a StackBlitz demo/source for Animated Ghosts Overlay:

Using Overlays, we can run both the fadeIn and fadeOut animations simultaneously… delivery a very slick user experience.

The downside to using overlays is that developers must choreograph when the ghosts are removed and fine-tune layouts to match the ‘real’ DOM layouts.

Solution: Inline Ghosts

Inline Ghosts use the same DOM elements to either show ghosts or ‘real’ data.

User list with only a partial load… loading still continues in background.

This is a CSS-only solution to render as ghosts. It should be noted that developers will face significant challenges to animate transitions between real vs ghost renderings.

Another significant advantage to Inline Ghosts are the ability to support partial, incremental data loads. Customers will be shown specific ghosts that highlight data still pending…

Here is a StackBlitz demo/source for Animated Inline Ghosts:

Using Inline Ghosts as Styles for DOM Elements

Solution: Inline Ghosts with Async Loads

If each record of server data is wrapped in an AsyncItem wrapper, we can treat our data items as having data lifecycles. This is especially useful for lists or presentational view components.

With data-level state, we can use Ghosts to indicate in-progress refreshes for specific data elements (and their associated view instances).

The server data remains unchanged yet is wrapped with extra information regarding state: uninitialized, loading, loaded, polling, error . We can even track cachedAt:Date values to track stale data and auto-refresh.

Tip: notice the use of a spinner class (Line #28) instead of the svg-icon while state.isPolling() === true .

Here is a StackBlitz demo/source for Animated Ghosts + AsyncItem: