Your poison of choice for building web UIs may vary, but one thing you can always depend on there being, is an ecosystem of feature-rich select boxes, popovers, modals, burger menus, and yes, date-pickers. I’ve been responsible for at least one of them.
Aside from the dark times when I had no idea what I was doing with the DOM and ended up using jQuery UI, along with some flirting with chosen, select2 and selectize, I’ve usually tended towards committing the cardinal sin of programming — implementing them for myself from scratch.
In the past my reasoning has been about perfectionism, i’ve wanted to control the display of these components so that they look at home in a design, but now I’m convinced there are stronger arguments. It’s mainly down to the typical lifecycle of a component from in-house solution to widely-used open source solution. Someone following this lifecycle may go through the following steps:
- They look at the options that are already available, conclude that none of them are an ideal fit, they support too many use cases or don’t follow the architectural conventions of their project.
- They write something from scratch that fulfils their requirements.
- They’re quite proud of what they’ve done, and it supports a different use case to the alternatives, so it’s obviously time to go and open source this sucker — it’ll raise the profile of either themselves or their company, ace.
- Before they do that, they clean up the code, because their first version wasn’t especially well written.
- They open source it, and nobody cares.
- They start making it more configurable so that it’s useful to more people, it inflates the file-size a bit and makes it a bit more complex for their own use cases, but it’s worth it — because along with their new super-slick demo page, these changes are enough to make people pay attention.
- They realise they didn’t do anything about accessibility, so they throw that in too, good job.
- Shit, localisation and internationalisation. Every string needs to be configurable, every date and number needs to be formatted correctly.
- Theming! Inline styles, or a stylesheet to download? This is hard!
- They’ve done it! Their component supports every conceivable use case, is fully accessible, every part can be customised in every way, and it works everywhere in the world. Oh, and it’s now the single biggest dependency in everyone’s project, except maybe for the framework they’re using.
- Someone else comes along, needing a component for a similar but not-identical use case. They look at the options that are already available, conclude that none of them are an ideal fit, they support too many use cases or don’t follow the architectural conventions of their project… wait…
What’s going wrong?
- Every project has its own approach to CSS architecture, now more than ever. In a React project someone could be using; old-school CSS, Sass, PostCSS, CSS Modules, inline styles, Radium, JSS, Aphrodite, etc. For a third-party component to be styled, it needs to provide some kind of API to allow this, this increases complexity and the amount of code.
- Likewise for internationalisation and localisation, the approaches people take to solving these problems vary widely, so API support is required for this as well.
- An exploding number of features is a big problem too. A date-picker is actually pretty simple to write — once you’ve figured out how to iterate over weeks or months, the rest is just DOM and a small amount of logic for date selection. If I never need the ability to select date ranges, then your third-party component that enables this is just creating unnecessary work for me and adding bloat. Select components are similar (if we discount accessibility features for now), you can write something that covers most of your requirements pretty quickly. And if you need to support remote data-loading, you’re going to need to figure out a good pattern for that anyway.
Third-party components do let us get up and running quickly, but the frustration using them always appears sooner than you’d think. So what’s the solution? I have two ideas, I think both may help:
- Release the code to your solutions, but don’t make them trivially installable. You want to make your code easy to follow, but you don’t want to support anything other than your own use cases. Documented example solutions to problems are hugely useful, and the benefits will grow as more of them appear. When people come to need something similar for themselves, they’ll be able to find some examples and use one of them as a starting point for their own requirements.
- Solve more lower-level problems, this doesn’t mean going as far as the almost farcical node.js nano-packages, but there’s a good compromise to be found. Date-pickers, select boxes etc all tend to require accessible popovers. The problems of positioning popovers and making them accessible are independent of the functional challenges of writing a good date-picker. If i’m going to write my own date-picker, having these problems solved will save a lot of time.
To elaborate on the second point, in functional terms, a date-picker looks something like this (forgive the weird syntax I just invented):
Datepicker = Selected<Date> + compose(AccessibleLayer, LayerPositioning, Calendar<Date>)
A select box looks something like this:
SelectBox = Selected<Option> + compose(AccessibleLayer, LayerPositioning, List<Option>)
When you look at how these components are composed, it becomes easier to see which problems will provide the most benefit when solved in a re-usable way.
One important caveat to mention. It‘s possible that your Calendar or List requires some knowledge of how it’s being used, selecting a date or option might require that you close your popover as well, a change in your options list might require a recalculation of layer positioning. I don’t have ideal solutions for these yet, so I welcome any discussion about it. There’s a few patterns i’ve explored, but I’m still ironing out the details.