TL;DR Popsicle did not get much love, possibly because we did not make it clear enough why we are trying to build yet another javascript UI library. We try to go into more details here.
One size does not fit all
When building backoffice web apps, we work with a very specific set of constraints, significantly different from the ones we have when working on customer facing websites/apps, such as:
- we have some level of control on which browsers will be used to access it;
- branding is usually not a big deal; this means we don’t need to worry too much about conforming to strict style guidelines;
- serving mobile clients may happen, but not very often; even when it is required, an ad-hoc mobile interface is usually a better way to ensure better usability.
All of this implies that it is feasible (and useful) to leverage ready-to-use components libraries to save time, provide a consistent user experience and keep a simpler codebase. Unfortunately we found the publicly available solutions lacking and, since we believe not to be the only ones experiencing this, we’re now considering building our own component based UI library for backoffice web apps, Popsicle.
Popsicle would provide a simple API to create nested component trees and render them to target DOM elements programmatically, using flexbox for layout. It would include a rich set of widgets pre-configured for common business cases, from remote-validation ready form fields to infinite-scroll grids with built-in sorting, pagination and filtering. We’ve begun working on it, but we’re trying to get some feedback before committing 100%.
Below we go into more details about what we don’t like about the solutions already on the market and what we’d like to build into Popsicle instead.
Conform, or be prepared to do the same work over and over again
On one extreme we have all-encompassing frameworks that force us to work “inside the box”. We’re given a specialized class system (that we need to learn how to use), a dependency injection mechanism, we need to create a new “Application” class and call into a complex framework just to render out a grid. What if we just want to integrate, incrementally, a specific component in our existing web application? The design of our software is needlessly complicated by having to adhere to the (sometimes questionable) structural convention or design patterns mandated by the framework.
Lots of magic happens behind the scene, and we need to learn a complex set of rules and conventions (dependency injection by name, dependency downloading, directory structure, scope, routing, defaults) to get little benefit (if any) over something simpler built just using the features of the language. As long as it works, and we keep ourselves within the boundaries imposed on me by the framework, it might be manageable, but as soon as something breaks or we need more freedom, then understanding our application, debugging it or extending it may suddenly prove challenging. Not all frameworks are so restrictive, often you can deploy a single component and opt-out of complex by-convention magic, but it is seldom self-evident how to do that and the documentation tends to guide you towards the “one true way”.
At the other end of the spectrum, we find ourselves working with “Just a Bunch Of Libraries”, and need to invest time and effort to wire them up together, over and over again. Maximum freedom, but repetitive and wasteful. Common things such as an infinite scroll grid with a remote Ajax json store take way too much effort to set up.
We’re looking for something in between, a wider UI library that brings together several vertical, specialized feature libraries, making it easy to work with them. Something that provides ready-to-use, barebone components that you can just instantiate and render wherever it makes sense for your application and interacts with your code via a clean API and event system.
Not invented here
Another issue we face over and over again is the tendency (especially among frameworks) to reinvent every possible wheel rather than reuse and leverage existing, well known, open source solutions: one could even see that as a possible frameworks lock-in tactic. This in turn forces us to learn new rules, syntaxes and generally overburdens us with redundant information.
There are infinite examples: templating engines, string formatting, build systems, dependency download mechanisms, charting, you name it. A special mention goes to layout engines, you’ll read about that below.
We’d like Popsicle to leverage existing solutions for these common problems and make it easy to integrate them, such as D3.js and charts.js for presenting data, or handlebar.js for templating, so that you can avoid learning our own and leverage what you already know.
No country for old browsers
While trying to reach the widest possible audience is a laudable goal, having to support older, legacy browsers is probably not worth it, especially for backoffice applications in an enterprise context, where basic security practices should enforce up-to-date, modern browsers for every employee.
We live in a finite world, and can either devote energy and time to develop something new and groundbreaking, or squander them making things work on IE6; we believe that usability, maintainability and correctness are more important than this kind of legacy support, especially when legacy also means insecure. We’d like Popsicle to be a library that looks forward, especially in this regard.
Simplicity
Once we get rid of older browsers, new options open up. No need to build a complex javascript layout engine if we can just use CSS3 flexbox and very little javascript for corner cases. Everything becomes simpler both for us building Popsicle (much less code to write) and for users, that now have one less new thing to learn when they want to understand, debug or hack components’ layout on the screen. As a bonus, we also have (very) limited need for polyfills or compatibility layers for things like SVG support, canvas, webforms, websockets, etc.
Do one thing, and do it well by default. Batteries included.
We are a very opinionated bunch and so is our software. We are not trying to please everyone: by reducing scope we can focus on the most valuable use cases for our target audience and create a better experience for both developers and end-users.
Our target domain requires few, easy to use, fully functional components that just work, without complex plugins, extra configuration and custom code. We want a grid component that does infinite scrolling by default, that can easily be told to infer columns configuration from a store metadata, that supports sorting and filtering out of the box, that talks JSON to REST APIs, and does that in a simple, scalable way.
Nice and (c)lean
Backoffice applications benefit greatly from a clean and simple interface that prioritizes readability and accessibility of content over glitz; this does not mean that it is ok for it to be ugly. A modern, pleasant UI can make the difference when trying to win a contract.
We should also keep in mind that no size fits all, and the concept of “pleasant” varies between industries, cultures, projects. This is why we’re aiming for a set of simple, lean, clean-looking components that are extremely easy to customize with regular CSS3 style sheets. Custom themes for different scenarios could then be created to make the best of both worlds (e.g. high-contrast themes for low visibility environments, small fonts themes, brand colored themes).
Freedom to tinker
We know from experience that even in well-thought, well-tested code there will always be things you’ll want to change (e.g. work around open bugs). We often find ourselves constrained by libraries and frameworks making functions and fields private, thus preventing us from tinkering, hacking, adapting it to our needs. Sometimes the reason is to “make sure that people don’t break things”.
We don’t subscribe to this condescending attitude, that tries to shield developers from themselves. A tool should make it easy and obvious to do the “right thing”, but shouldn’t assume to know what “right” means for everyone else and should leave expert developers free to do what they need or want.
We want Popsicle to be open for tinkering, poking and hacking, so that when you need to do something out of the ordinary, you don’t need to go through any extra hoops. You can decide to replace templates or even the templating engine, extend or alter the pagination behaviour, override defaults if you need to.
What now?
We’re thinking about building a demo “pet shop” project (coded againts a mock API) to give a better idea of what we aim to achieve with this.
If this looks interesting and you want to know more, we encourage you to go over popsicle.io and register to get timely updates on our little experiment.
Infrequently asked questions
How would I get the widgets in the view?
You either call render on a widget passing a dom element (i.e: widget.render(body)
) or just add a widget to a widget either programmatically (i.e: widget.add(anotherWidget)
) or by configuration (i.e: Popsicle.create({ root: body, widget: 'panel', body: [{widget: 'panel' ... }] })
)
Can I nest widgets?
Definitely, this is a core aspect we have in mind.
Can I style widgets?
yes, you can add a custom class to a widget, override default styles, or even change the handlebars template for that widget.
How hard is it to change widget behaviours?
You can react to events by registering listeners, prevent default behaviours by returning false from a listener, or just subclass a widget and override the default handlers. Keep in mind that nothing in Popsicle is intentionally made private.
What is the “group” widget doing in the form example?
It creates a fieldgroup containing other field widgets (an email field in this case). This creates an extra DOM container element and changes the way inner fields are serialized, by nesting them in a “group” object.