A story of working with design systems in the web for 15+ years.
Starting in a time when NPM didn’t exist, when Javascript didn’t have “classes”, when CoffeeScript was declining, Typescript wasn’t ever thought of and “Design System” wasn’t an existing term … then I learned the most about them.
During my software engineering apprenticeship (2005 – 2007) I learned Java with Eclipse and later build applications on that platform. The UI is build with SWT and JFace.
I liked the Java experience, it teaches valuable lessons but I call the web my home and so I started porting SWT/JFace into web technologies. I wanted a 1:1 port as much as possible and saw myself confronted with quite some challenges. The web at that time had no classes (essential for Java), no modules for separation (packages), no import/export (no resolver to deal with deadlocks), no interfaces (which I like).
I could use base2 by Dean Edwards as my start and build the rest I needed on top (my own namespace and class system with interfaces). I built a component library named gara. Here is a snippet for a component:
"use strict";
gara.provide("gara.widgets.List", "gara.widgets.Composite");
gara.use("gara.widgets.ListItem");
gara.Class("gara.widgets.List", function () { return {
$extends : gara.widgets.Composite,
$constructor : function (parent, style) {
// ...
}
};});
It wasn’t the time of declarative code, here are the components in action (full code):
// buttons
new gara.widgets.Button(buttons).setText("Simple Button");
new gara.widgets.Button(buttons).setText("Simple Button width Image").setImage(imgInfo);
// TabItems
new gara.widgets.TabItem(tab).setText("List Widget").setControl(list);
// List Widget
list = new gara.widgets.List(tab, gara.CHECK | gara.MULTI | gara.FULL_SELECTION); //
new gara.widgets.ListItem(list).setText("Item 1");
Checking out the code it is immediately runnable (no need for npm install
shenanigans), the lib
directory contains the – what I consider too many – 8 dependencies (imagine this today).
That’s a screenshot in a modern browser so some layout is a bit off, because gara works best in IE6.
My Components don’t Sound Like a Menu from Starbucks
A notable difference to today is naming conventions. Today you can ask your team about the name for one component and get 186 answers (as Amy Hupe showed). Of course everybody has an opinionated answer, and everybody is right and that has led into a situation where components of a design system sound more like a menu from Starbucks rather than what they actually are.
SWT as per Java mechanics used class inheritance and they did an amazing job in getting that part right. I had an enlightening moment when realising they followed the ARIA class diagram as much as possible. These terms stand the test of time and are as much as accurate back then and today. Little do people know about controls, composites or windows these days, let alone their relevance for composition, lay-outing or keyboard navigation (learn that when you are building UIs, that’s your bread’n’butter).
Despite ARIA classes making logically sense, it also teached accessibility on a comfortable, subtle note. It went so far that I threw my initial implementation over board and reworked the internals with accessibility in mind and I am recycling parts of this code 15 years later (more on that in a future post).
JFace/Viewers = (Framework) Reactivity
SWT is the package for manually building user interfaces and requires high manual efforts adding, removing and resorting items in composites. Luckily they provide a partner package JFace to help with two way binding to connect your data with UIs along with necessary data transforms.
In today’s frontend development, this is addressed through reactivity solutions. And we all benefit from the TC 39 signals announcement/working group where major frameworks and library authors are collaborating.
Back in the days, the absence of such led me to abandon gara. Until I learned about a demo showcasing hundreds of input fields and changing one value changed them in all inputs from SproutCore (with horribly poor performance). That closes a nice circle for me, as I love using Ember.js these days (which was born out of SproutCore).
Multiplattform = Multiframework
Java is known for its “write once, run anywhere” mentality. The web is another universal runtime but recently I observe a split.
For one I see more and more engineers show their experience in frameworks rather than knowledge about the web platform. In the same breath those tend to take the replacement of programming languages, aka the phrase “I do program in Elixir/Java/Rust/…” has turned into “I do program in Next/Vue/Svelte…” (… why they chose php3 again?).
On the other side the highly intrinsically motivated folks who drive the universal (agnostic) approach and in a second effort provide API layers for respective frameworks. First noticed at Ember’s own warp drive (previously ember-data) and the fine folks over at vue with shiki or volar – to name a few examples (there’s plenty more).
As part of my research design system hokulea I architected it in a way to have a core layer containing web fundamentals (CSS + JS) and a thin API layer per framework.
Conclusion
After 15+ years, the following is still unchanged: Focussing on frameworks will miss the point of the underlying technological platform and constrains your thinking. Go universal instead and craft proper APIs to integrate reactivity solutions with your frameworks. Do your research and get familiar with ARIA/accessibility, names and concepts; it will have a sustainable impact on your systems maintainability as well as your customers experience.