We’d like to talk a little about how we’ve been addressing working with UI elements using a highly componentised approach, and how Aurelia is really helpful to get you into that kind of thinking.
When we talk about a highly componentised approach, we mean how every element that is bound to appear in more than one place in our UI should be encapsulated into its own component. And even things that will not appear in more than one place, but represent a distinct visual or interface function.
No matter how insignificant one such component may seem, chances are it will grow and evolve in the future. You want to keep your codebase DRY, and your code easy to understand.
An illustrative example for us would be the follow button one can use in Ployst to follow/unfollow a stream. Initially it looked just like a toggleable option that could be implemented as a checkbox directly as part of a stream component (e.g. the stream card we use when we display a list of available streams). But once that code (both presentational and behavioural) starts getting mixed up in the stream component, it becomes hard to reuse - we all know that when in a hurry, some developers may be tempted to use “reuse by copy paste” and end up with a harder to maintain codebase, inconsistent presentation etc.
The Aurelia way
In Aurelia, custom components are very easy to create, and based on the convention of having two matched files with the same base name:
- Presentation: HTML markup (e.g.
follow-button.html) - in Aurelia parlance, the view
follow-button.js) - Aurelia calls this the view-model
Aurelia is really strong on both convention and separation of concerns. This makes it easy to structure your codebase cleanly, and there is much to thank for the thought that has been put into the framework.
This, as an example, is our
blip-card.html, where we display
a blip (the basic abstraction for any type of message in
require tags at the top represent the components we import
into the page. Notice that in some cases, we import an
and in others the extension is missing: in this second case, Aurelia
will load a custom component with both the
as outlined earlier.
You can see in the example how easy it is to understand the content
of that component, because the markup is so simple, and has semantic
content: things are named for what they represent (e.g.
You don’t get lost in the details of how these are implemented using
actual HTML tags, classes etc.
The case of our Follow button
We decided to make the follow button its own component from the beginning. This was probably the first instance of an element that was very simple, only used in one place, but had potential for growing and becoming more pervasive.
Its apperance was naive (a bootstrap button), and the code was simple enough. These were the off and on states:
This was the original code for the view and view-model:
And this is what is needed to use this button:
Over time, all of the following things happened:
- We started using the button both on a list of available streams and on individual stream pages
- We changed the appearance of the button
- We added the number of followers on the side of the button
- We added displaying a list of followers on hover
All of these changes to the button’s behaviour and appearance required no modification of the using code, and were fully isolated inside the component itself.
This is what the button looks like nowadays, when hovered upon:
As a conclusion, my advice to you is to think in terms of components, no matter how small these seem to be, and your code will be easier to read, maintain and grow.