26th Mar 2015
Building interface previews with ReactDesign pattern & small CSS lib for interface previews
Since my last post I've been experimenting with different ways interface previews can be implemented. For the purpose of this post I'll use react because a) its amazing and b) the underlying principles I cover can be applied to other JS frameworks with relative ease.
Refining the implementation
Initially I thought the cleanest approach was separating placeholder elements from the real ones. For example this interface:
Would have the following code:
this.state.data_arrived is a state variable initially set to false and then set to true once data from the server has arrived.
The principles behind this are good:
- Separation of concerns (inside templates)
- Can disable interactions (stop buttons / form elements from being used before page is ready)
However templates get bloated as they contain two sets of mark up - one for their preview state and one for when the data they show has arrived. Having used interface previews more and more I realised there must be a smarter method of showing placeholder elements. In an ideal world there needed to be one template without any conditional logic inside it, which contained only one set of elements. This mean't elements needed to become declarative.
In terms of interface previews declarative elements should only have one set of mark up. The same mark up should be used whilst the element is waiting for its data and when it's data has arrived.
Previously I said "the structure of the element is generally different for its two states". However I've found increasingly that this isn't the case. The structure of elements and how they are positioned is always the same; its the values they show that are different.
Here we can see the profile image always sits to the left of the persons name. As each layout is the same it would be nice if both shared the same mark up. This is where declarative elements come into play. What I really want is to specify an image and a heading in the template once. Something like this:
If the profile image and name aren't available show the placeholder image and placeholder heading in the meantime. The problem with using the snippet above is that this.data is undefined on the initial render (as it wouldn't have arrived from the server yet). If we delay the render until it does arrive we are blocking the UI.yuck!
A solution I've nicknamed "Preact" overcomes this by moving the server dependent props out of the template. Props are assigned to companion variables that are initially declared without values. These variables can be used in the template on the initial render (when they are empty) and on the second render when they contain values. Declaring variables in one place also makes it easier to see what a component will show.
Note: Arrays need to be initialised with an empty array so that operations like .map / .each can be used in the template on the initial render.
You'll notice that the image is a react component rather than a normal image tag - we'll get to this in a bit
Here we have one template that is rendered when we are waiting for data and again when it has arrived. The templates concern is what it should show, and not how it will show it. We have described what the layout should look like without hard-coding its implementation; hence the term declarative elements.
To give this component a preview we can give it a conditional class whilst its waiting for data. Any elements inside it that wish to have previews can also be given a class.
React provided a utility for this as part of its addons called classSet
Here the component will have the class waiting-on-data whilst data_arrived is false, which allows us to style anything inside it that has the class with-preview. Boilerplate styles for element previews can be found here.
Pointer events to the rescue
We can also add the class disabled-in-preview to any elements that a user shouldn't be able to use whilst the component is in its preview state. For example:
Elements with the class disabled-in-preview have their (CSS) hover/active states, and (JS) click/focus/tap events prevented using the highly under-rated CSS property pointer-events. In this example the click event editUser won't register until the waiting-on-data class is removed from the parent div. This class can also be used to modify the elements appearance in its disabled state; reducing the opacity usually does the trick.
The image component simply returns a placeholder image or an actual image depending on whether src props exists. The width and height are also passed in as props so that the placeholder image is the same size as the actual image. The width and height could alternatively be explicitly set in CSS.
The placeholder image and image sit inside a wrapper with the class preact-image-mask, so use this when adding your own styles on top of the boilerplate ones.
Interface previews make a debut in CommuSoft
We have been eagerly anticipating interface previews in CommuSoft for a while now, and this week they made their first appearance! They've been used in a new context too - broadening the use cases in which interface previews can be used. (The emphasis till now has always been on page load).
A crucial part of the diary is being able to add events to it quickly. Part of this process is selecting which property the event will take place at. Some users can have up to 60,000 properties, so the search needs some magic to make it feel quick a.k.a perceived speed. Heres a sneak peak:
As soon as you begin typing in the search input, placeholder results are shown immediately and remain showing until the results have come back from the server. This greatly reduces the perception of how long it takes to get the list of properties, and if anything spruces up the interface for us.
It would be fair to say I'm still early into my research of finding the best ways of implementing interface previews. In my opinion the preact approach comes up trumps, as it reduces the complexity in which they can be used; which in turn betters the developer experience. It would be great to get your thoughts & ideas of how the approaches discussed could be refined further.
A demo interface built using the preact pattern along with source code can be found here .