January 18, 2024

Elements - not so elementary. Part 1

Erez Reznikov
To function properly, interactive elements need to be structured in a specific way. To just appear visually - they don’t. This has been breaking handoff processes for years.
Elements - not so elementary. Part 1

This is part 1 of a two-part post series. Part 2 is here

Dmitri Mendeleev’s periodic table looks simple, it doesn’t strike as if the elements are in fact significantly different from one another. But when you dig in and understand that just ‘seemingly insignificant’ property of the number of electrons and protons makes for a vast difference in the way each element acts and reacts in proximity to others - you get a taste of how a harmless looking list can hide all the relevant complexity.

Periodic table of elements

Interactive elements - the building blocks of websites and applications - have the same illusive property. If you look at any of the ‘checklist’ websites, repositories, posts on social media and blogs - you might have the impression that it’s all just arrangements of frames, icons and text. That would miss most of the complexity.

In this post (part 1) I am going to show some examples of the divergence between how code and visual design tools treat interactive elements and components in general.

Curiously, the root of the problem often remains hidden from both the siloed designers and developers and only becomes apparent when you try to compare and communicate about it. This post is one example of such effort.

Simple but with quirks

As an example let’s look at 3 super simple elements - a checkbox, a radio button and a toggle switch:

checkbox toggle and radio button image

Since the web version of all these elements was created in the beginning of the web itself, some 30+ years ago, there were a lot of defaults that were decided upon for overall use, so to this day if you want to style a checkbox or a radio button end-to-end in a custom way that differs much from the browsers defaults you’d have to do a few surprising things:

  1. You would have to to use a container (usually a <label> to house everything you want to activate it to be within)
  2. To make the actual default appearance of the [input-type =radio] hidden from the users you can be forced to do either of 2 things: reducing opacity and size to 0 when you need to create a new div with content instead of the actual input; or in simpler cases use ‘appearance: none’ (appearance property controls the set of default styling of browsers in different operating systems Chrome/Firefox, macOS/Windows will affect it) if you only need to restyle the input itself (might be enough for radio buttons, but not checkboxes).
code example of hiding the source input
  1. Either restyle in case you’re using ‘appearance:none’, or recreate the design you want with a div and a custom icon.

Only then will your design be both on-brand, custom and persistent across devices, browsers and operating systems. You’d have to use the input node itself only for its embedded functionality that browsers automatically recognize and afford the user to interact with.

It’s even more non-trivial with toggle buttons, since they don’t actually exist as a standalone web element. Using much the same hiding tactics - every time you’ve toggled something online, you were pressing a hidden [input-type=checkbox] inside. Yep, all toggles are actually redesigned checkboxes as far as the browser is concerned.

code example to show that toggle is actually a checkbox

The states of these basic elements are specific, and are baked in by the functionality of the web itself (checked/unchecked). Their names are set and permanent and they are not variants of the same checkbox, as size and color would be.

Contrast this with how a designer approaches these 3 elements in a vector based design tool. What’s a checkbox visually? A frame with an icon. The different states are just variants, indistinguishable from other potential visual variants. To add labels and helper text you’d probably want to house them together in a frame, use auto layout in 2 stages and be done.

checkbox variatns tree

A radio button is even easier - you don’t even need a vector icon inside, just the rim.

radio button in Figma

A toggle has no checkbox inside, just a toggle frame and a knob. You might forget states like focus and disabled, and most designers forget to include the 'indeterminate' state when designing them.

Toggle in Figma

There’s more complication still: For the real product code, you’d really have to decide what is placed inside or outside the <label> container since it’s going to affect where the actual ‘click’ is going to affect the state of the checkbox/radio/toggle so the layout itself will be guided by functionality, not by how comfortable it is to express something using auto-layout.

trigger areas example

In our example here, it’s more comfortable to put the label and the helper text in the same frame but in terms of functionality you might not want your helper text to also trigger the checkbox state, so you’d have to re-arrange the layout to make the helper out of the <label> and therefore not affecting the selection.

It’s usually the case that a designer will structure the element as it makes sense in a visual design tool, and afterwards hand the designs over to the devs. The devs will most likely look at the visual final result, inspect measurements, download relevant assets if needed, look at the layer structure, see that it’s not helpful for them, disregard and create their own correct structure and try their best to make it visually identical.

Mo’ complex - mo’ problems!

To custom-style any element that is a tad more complex such as a select you’d have to hide many more native html nodes to style your own instead of them, and you can’t get away with just css, you’d have to employ JS to make it work. You also have to take care about a whole slew of interaction design decisions like how the box of options will be positioned over the select itself, what would be the condition when it flips if it can’t be opened to the default side, Is the dropdown multi select or single, how is it sorted, how autocomplete looks, does the box auto focuses on some condition, does the options box has a max height or number of items etc.

And that’s not just me saying, take a look at this quote from MDN web docs by Mozilla (which is probably one of the most comprehensive and trusted sources documenting Web platform technologies, and are open-source and collaborative). From the section ‘styling with css’ of the select page. [Emphasis mine]:

The <select> element is notoriously difficult to style productively with CSS. You can affect certain aspects like any element — for example, manipulating the box model, the displayed font, etc., and you can use the appearance property to remove the default system appearance. However, these properties don't produce a consistent result across browsers, and it is hard to do things like line different types of form element up with one another in a column. The <select> element's internal structure is complex, and hard to control.

select box variant tree

Contrast it with how a designer usually treats select boxes in design tools’ design systems? Just a frame with a text in some variants to specify states (interactive, open, closed) and visual variants (size, style, importance maybe). Designers will compose the box of options as a simple frame of another ‘option’ component with several states - and be done. All fairly ‘what you see is what you get’ here.

Like oil and water?

All of these differences are just a small example that illustrates why it was basically a rigged game to begin with. Design tools developed to optimize for intuitive expressiveness, ease of ad-hoc manipulation, even at the expense of control, robust modularity and binding rules that mimic the web standards. HTML, CSS and later on React and other JS frameworks developed to achieve effective - sometimes tailored and sometimes generic - methods to express elements and manipulate them as needed. These are completely different properties to optimize for, so no wonder these distinct evolution processes produced very different ways to render the structure of interactive elements.

The more I dive into it, the mere fact that we managed to handoff designs and build something worthy with starting conditions like these - looks more and more like a small miracle to me!

In Part 2 I’m going to elaborate on some more ways communicating about components and elements is difficult, why classification is non-trivial, but chiefly about why that matters so much. Why the consequences of this difference are so important. To be on the positive side - I’ll compare two ways I see our industry is trying to overcome this problem, and which I prefer more. I’ll also provide links to valuable resources to help designers be more mindful of the caveats.

See you in the next one :)