Improved UX with Ghost Elements + Angular 7 Animations

Customers are immediately presented with layout flows that are consistent regardless of renderings with ghost or ‘real’ elements.Ghost List using @angular/flex-layout + gradient fades & animationsPlanning for Ghost ViewsGreat UX uses more than static ghost elements… and even more than animated CSS gradients in the elements placeholders.Great UX requires developers to consider animations for both the ghost elements AND the real elements.Great UX solutions leverage the super-powers of Angular AnimationsDevelopers can create Ghost (aka Skeleton) views in three (3) ways:Ghost Overlays use separate, distinct view components to render either the ghost DOM..These components usually overlay/underlay the real DOM that is pendingInline Ghosts use the same DOM elements to show either ghosts or ‘real’ DOM with business data.Inline Ghosts with Async Loads use ‘data wrappers’ to allow data items to track state… state the will be reflected in the view components.Application ScenarioLet’s create a simple application and then add features.Our Angular 7 application will load mock user data from an online service and then use *ngFor to show an Employee list.List of mock users using Angular HttpClient + @angular/flex-layoutNow let’s add features to this application:Use @angular/flex-layout to create 2 columnsSimulate a slow network with a 2–5 sec data loadAnimate the list to stagger and slide-fade-in each row..Here is a fadeIn animation (with slideIn and stagger) that will animation the row as each user is added to the DOM:Now let’s prepare our real users-list.component view:This is great… except that the simulated network delay gives us a BLANK page while the data is loading.Now we are ready to use Ghost views to solve this UX disaster!Solution: Ghost OverlaysGhost Overlays use separate, distinct view components to render either the real DOM or the ghost DOM.Ghost List is an overlay DOM groupThis 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 GhostsInline 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:Solution: Inline Ghosts with Async LoadsIf 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:SummaryWhat are some takeaways from these ^ examples?With good animations, Ghost views dramatically improve customer UX.Angular Animations can be implemented as reusable recipes: src/utils/animations/fade-animations.scssAsyncItem<T> is a wrapper interface used to decorator server entity items with ‘client-side data state’.Each Ghost component (a grouping of 1…n ghost elements) is custom crafted for specific ‘real’ views..Ghost components are not reusable.Ghost gradients and animations, however, are reusable: src/utils/animations/ghost-animations.scssGhosts may be implemented as both a view component + CSS: src/app/user-list/ghost/ghost-list.component.ts/scssGhosts may be simply just CSS: src/app/user-list/ghost/ghost-item.component.scssWith these ideas, developers are now prepared to start implementing and using Ghosts in their own Angular UX and PWAs..????Ghosts + AsyncItem + NgRxIf you are using NgRx, the next step is to plan and implement ghosts, synchronize your data-states + view component states, and integrate all those features into your NgRx solutions.Call us at Nrwl.io to learn how Nrwl can help reduce your products’ technical debt, add performant NgRx to your features, and improve your UX, testing, and team collaborations… deploying better products, faster.And for those enterprise teams interested in using NgRx with Ghosts + AsyncItem, please contact Thomas@Nrwl.io or Jeff@Nrwl.io.Community KudosHuge shout outs to Max Lynch, Adam Bradley, Mike Hartington, and The ionic team for StencilJS and the Ionic 4 with Angular.And a distinct, super-huge shout out to Matias Niemelä for architecting Angular Animations.There are some amazing articles for developers wanting to learn more about progressive-loading, skeletons, and user-perceptions related to progressive-loading:How the Facebook Content-Placeholder WorksBuilding Skeleton Screens with CSS Custom PropertiesImproved Perceived Performance with Skeleton ScreensStencilJS Skeleton-Text ComponentA Bone to Pick with Skeleton Screens. More details

Leave a Reply