UI library development in the frontend wonderland

Gal Blond
Yotpo Engineering
Published in
8 min readNov 1, 2022

Imagine yourself, standing in front of a crowd of people, each from a different nationality, speaking their native language. Now imagine trying to explain to them what your favorite dish is, or how you like to drink your coffee. A bit difficult, isn’t it?

Now reflect on the world of JavaScript frameworks today, like Angular, React, or VueJS, and think how impossible it is to write something that every framework or library would understand.

This is the true Babylon of modern web development.

As a Frontend Infrastructure Engineer at Yotpo, in the last year I’ve gotten to dive deep into the world of tech-agnostic frontend solutions. As part of Yotpo’s shift in focus to DevEX, we decided to build a UI Component Library that can be used across the company.

In this post I’ll take you through my journey building Yotpo’s UI Library — Yotpo’s Design System Component Library, the research, the difficulties, and the victories in the world of modern Frontend development.

Cross-framework solutions in the modern day

Frontend development is booming, and once you dive into it, you see you’ve got a lot of tools to play with. As the years go by, more solutions are being developed, and we need to navigate between more frameworks, libraries, and other solutions to reach our best development.

Babylon of frameworks and libraries

Take this case for example…

Your company is developing a highly complex web system using Angular. But in several years from now, a better frontend framework will be released to the market and everyone will want to use this shiny new toy.

You might consider developing new projects with this new framework or even migrating some existing projects to it. It will probably be extremely difficult to migrate the whole codebase to the new framework, and you’ll find yourself in a vendor lock-in — stuck with your existing framework because the cost of switching to another is too high. Then you’ll need to handle two frameworks, and perhaps even more.

As the big players dominate the frontend framework market for an average of 8–10 years, this is bound to happen to all of us at some point.

How wonderful would it be if you could write something once and reuse it everywhere, no matter the framework or library you’re working with, or even without any at all.

The lion, the witch and the Atomic Design Pattern

When we think of reusable code, we first think of the shared parts of a system — its building blocks. In the frontend world, our most obvious building blocks are the components that create our application.
According to the Atomic Design Pattern, you can better understand the structure of a system by dividing it into its units, and grouping them by complexity and containment.

Once we have those groups and elements listed, we can see that around 70% of them are shallow components that can be created easily. A technology known for its simplicity and efficiency when creating web components, is Web Components (pun intended).

Web Components, the ultimate solution

Web Components are the lightest form of components. They’re actually a combination of JavaScript code, encapsulated CSS, and an HTML template as an individual unit.

Because they’re the bare-bones technology of web development, they are readable by all modern browsers and can be used in the most popular frameworks.

Thorough exploration of Web Components solutions

At this point you must be asking yourself, how does this magic actually work? Let’s dive deeper into what web component technology offers and the several ways it’s used in the industry today.

How do Web Components work?

Web Components consist of three main technologies: Custom Elements, Shadow DOM, and HTML Templates. Those technologies are imitated and used by a lot of other frameworks today. It can be style encapsulation, passing of data, or rendering a template. In the end, those principles are no different than the ones you already know from other frontend frameworks.

Alice in Web Components wonderland

You’d be surprised by how many solutions there are in the field of Web Components.

When I started my journey in this wonderland, I was amazed by the amount of projects being developed using Web Components. Throughout this research I’ve also tried a lot of the techniques used in them.

You can roughly categorize the technologies in the Web Components field to Framework-based solutions and Web Component-based solutions.
In my research, I focused on the two most popular frontend frameworks at the moment — Angular and React.

Framework-based solutions
They have native framework components at their core, and convert them into a Web Component. The core of these solutions is specific wrappers that translate each component’s events and properties into a Web Component, so other frameworks will be able to use them.

There are some tools that do the transformation for us.

Angular, for example, has its own tool — Angular Elements. But the main problem with these solutions is that they load a version of the framework in the background.

“We are working on custom elements that can be used by web apps built on other frameworks. A minimal, self-contained version of the Angular framework is injected as a service to support the component’s change-detection and data-binding functionality.” ~ Angular Elements Documentation.

This is why these types of solutions seem less effective to our needs.

Web Component-based solutions
These are based on Web Components technology. Writing native Web Components could be a great solution if it wasn’t a bit difficult. Handling an inner state, complex properties, and events can require a lot of code and effort.

“Web Components can be hard to write from scratch. There’s a lot to think about, and writing a component can require a lot of boilerplate code.” ~ webcomponents.org Documentation.

There are libraries that wrap the Web Component technology and allow a straightforward creation of custom elements. Some of those libraries have strong communities, making it easy to find code examples and help. Every library excels at other points, and with a deeper look into their documentation you can find which one will serve you best.

How do you choose an ideal solution?

Before choosing a solution, you should tackle the issues that might occur in the field of solutions you’re looking at. In our Web Components Solutions, there are several issues you might want to consider before choosing a specific solution. As previously mentioned, these solutions are meant to help build a shallow and simple component library.

I’ve looked closely at each of the above issues in my research, and the summary of it is right before your eyes! I’d like to share with you what I discovered as I dove deeper into several of them:

Component complexity
Creating components can require a rich logic and maintenance of different states, events, data structures, etc. As mentioned above, this is very hard to achieve when writing a native Web Component, but easy when using a base library or writing a component in a popular framework.

Optimized bundle size
When consuming a UI Library, one of the key features should be its bundle size. We can have a great solution like Angular Elements, for example, which allows us to create complex components. But when loaded in React, it loads a minimized version of Angular — something unnecessary that other solutions solve.

Easy to use in popular frameworks/libraries
This solution must be a tech-agnostic solution, and an easy one. In React, for example, the Event system is registering Synthetic Events fired by React components, making it impossible to register DOM Events fired by a custom element. It requires some technology that can transfer those events to the “understandable” event system.

Building a Web Components UI Library

Finally, let’s talk about the solution we’ve built.

It consists of three libraries:

Core Library based on Web Components

The core development of the library is done using Lit, which is a Web Component-based Library. It is actively maintained and creates a good balance between performance, developer experience and feature richness. It has an extended component’s update cycle, good handling of events and states, and is well-documented within a strong community. All of the components in the library, from the smallest button to the complex dropdown and table, are written in Lit.

Each component is exported individually — shared code is written once and imported by all using components — allowing tree shakable importing and small bundle size.

We’ve also used Storybook to present our components in a friendly environment.

Wrapping library for Angular

As previously mentioned, Web Components don’t require a wrapper in Angular. But we’ve created a wrapping Module for each component, so it will be consumed by Angular developers as a native Module.

We’ve also created a CUSTOM_VALUE_ACCESSOR, allowing the Form Elements as Input, TextArea, Checkbox, etc., to be used inside Angular Forms as if they were Angular’s native Form Controls.

Angular users are only requested to import the wrapping library, apply the CUSTOM_ELEMENTS_SCHEMA to the Module where the components are used, and just let the magic happen.

Wrapping library for React

For React we’ve created a wrapping library that wraps the Web Component as a React component.

The wrapper itself, as you can see below, is also part of Lit’s development, and is very straightforward and easy to use. The wrapper allows React users to pass properties to the Web Components, using the React syntax and listening to DOM Events fired by the components. As mentioned above, because React implements its own synthetic event system, it cannot listen for DOM events coming from Custom Elements without the use of a workaround, which is the main reason for creating the wrapper.

What’s around the corner

After the journey I’ve taken walking the Web Components brick road, I’m still wondering where the rest of this road will take me.

I don’t believe Web Components will replace the usage of frameworks. The need for complex and rich frontend logic will always be there, and although you can gain a lot from using them, Web Components are not always a perfect fit. But in a lot of cases, like ours, creating a UI Library with framework-based components can be overkill, and just a waste of space and time.

As the years pass, more and more frontend frameworks and technologies are created, and the need for tech-agnostic solutions increases. It also looks like there’s an obvious increase in the use of custom elements in web development, and a lot of companies investing in learning and building them.

As they are part of web standards, I believe that Web Components are here to stay. Frontend development has reached its peak, and in the years to come I hope to see far more cross-framework solutions that will enable all of us to understand each other and work together easily.

--

--