Building a Component Library: Our Experience

in marketgoo News & Updates. Last Updated on December 17th, 2019

Our new design system Ola, which my esteemed colleague Oscar talked about in this post, has allowed us to solve the design coherence issues we had with our interfaces.

​In this post I’ll explain our experience with developing and implementing Ola in our products, discuss some mistakes we’ve made and also give out some advice in case you’re planning on creating your own component library.

The Beginnings of the Component Library

We were sure that the best way to implement Ola in a cross-disciplinary way would be through a component library that we could share among different projects, and comply with Ola while avoiding rewriting code.

We used React to develop the components, which is the library used in all our products. We also decided to wait until it was mature before doing an open-source release, and so we began working in a private GitLab repository.

At first, our way of organizing work consisted in developing a component (e.g. Button) in HTML and CSS following our CSS methodology, in order to then convert it into a React component. After verifying with the Design team that it complied with Ola specifications, then we’d use it in projects, replacing the older component.

First Implementation Problems

As the project was still in its initial phases, we didn’t want to distribute npm versions just yet, so we used GitLab’s CI to publish nightly builds automatically with every commit.

We had a pipeline prepared in GitLab for each change, so as soon as a commit was pushed to the development branch, it automatically packaged the project as a nightly build and published it to a URL that we’d call from package.json.

// nightly build installation with yarn 
yarn add

​// Part of the package.json after Ola installation 

  "@ola": "" 

This seemed like a good idea to start with, but turned out to be a mistake that caused a few problems, for instance:

  • Both npm and yarn check the integrity of the installed packages through a hash, which in our case changes for each commit. This meant that sometimes we had errors if the hash stored in package-lock.json didn’t coincide with the one from the downloaded nightly.tgz.
  • Using the above-mentioned URL in production meant that in each deployment of our products, the latest nightly build was always used, and this caused a bug due to pushing changes into the development branch that we didn’t want to publish yet.
  • Since there were no numbered versions, yarn failed when we wanted to update the nightly because it didn’t properly clear the cache. (This is still an open issue for yarn). The solution we came up with for the cache issue was using this command:


yarn cache clean @ola && cache=$(yarn cache dir) && [ "$cache" != "" ] && [ -d "$cache/.tmp" ] && rm -rf "$cache/.tmp" && yarn add

We realized that having the library published as soon as possible on npm, using versions, solved these issues. Once we released it, we moved the project to GitHub.

Component Testing

In this library, the components hardly contained any logic. The Tag component is just a span element in which you can change the class that will render with the variant property.

​Since there was practically no logic involved, we initially didn’t see the value in using libraries such as airbnb’s enzyme to do shallow rendering and to check that the components were rendering correctly.

We wanted to try Jest and its snapshot feature, and are currently happy with it. What we most value is that we can easily and quickly write tests for each property, with the confidence that if something is eliminated, the test will call attention to an incompatibility. Additionally, each component has its tests in the same directory as the rest of the code, which makes it easier and more comfortable to do tests.

// Current testing process 
- 1st Write the tests in the `test.js` file, stored in the same 
directory as the component we’re testing. 

- 2nd Jest generates the snapshot of the component automatically 
the first time the text is executed. 

- 3rd the following times, it verifies that the snapshot created 
initially coincides with the current one, showing an error if it’s not.

Once we have components that contain more logic or interactions, we’ll combine this type of testing with a library that’s more focused on E2E.

We’re also using Browserstack to check that our components are working correctly in all the browsers that we currently support.

Browserstack, just like other tools we use (like TravisCI) is completely free if your project is OpenSource.

Must-Follow Rules for the correct development of components

These are some of the best practises we learned as we developed the library:

Avoid passing nodes through props, if they can be children


<Panel title="My title" />​

<Panel>My title</Panel>

As tempting as it may seem to pass a string as a prop to, for instance, paint a title, it limits the flexibility of your component since it no longer allows for more complex compositions. What if we want to include a button or icon? Add more props such as iconTitle or buttonTitle? It’s best not to use props for the component to then generate subcomponents, but instead pass the components directly through children.

<Panel title="My title" iconTitle="close" onClick=... />​

  My title 
  <Button onClick={() => {}}><Icon variant="close"/></Button> 

We should only pass nodes through props when we want to do a composition and need multiple children. In these cases, the property must be as generic as possible:

//Bad: can we only add icons? 
<Panel icon={<Icon />}>My title</Panel>​

//Good: the "extra" property allows anything 
<Panel extra={<Icon />}>My title</Panel>

Spread the remaining props

It doesn’t make sense to repeat props that can be passed to the underlying component. It’s much more efficient to pass the props especially when the components are wrappers of native elements, whose attributes should not be renamed.


//Bad: we’re renaming the native properties of the Button, 
such as disabled 

const myButton = ({ variant, onClickButton, isDisabled }) => { 

  return ( 
    <button variant={variant} disabled={isDisabled} onClick={onClickButton} /> 

​//Good: we’re using native properties, even those which we hadn’t 
taken into account before (autofocus, type, value...) 
const myButton = (variant, {...props}) => { 
  return ( 
    <button variant={variant} {...props}> 

The Component Documentation

It’s important to have solid documentation and be able to show each component and its characteristics working separately, so that the learning curve is not overly steep. As of today, tools such as Storybook or Styleguidist have very similar characteristics, and are two of the best tools to document components. The best part is that they allow you to automatically document components and their props.

When we were selecting a documentation tool, we looked at Styleguidist which was more focused on the writing aspect of documentation and Storybook which seemed to be a better fit with our needs – focusing more on development, offering tools and powerful plugins to simulate statuses, data and to adjust props.

Open Source

From the very start, our intent was to release Ola as an open source project, since there are many advantages that come with open source:

  • Free tools (TravisCI, Browserstack among many others)
  • Ease of integrating someone new into the team with a well documented project
  • Feedback from the user community that uses our software


​A component library is truly appreciated when it’s fully (or almost fully) implemented and working. Ola allows us to develop faster, without worrying about design details, without rewriting code, and fostering daily learning in order to improve our components.

Team that built component library
The Ola champs at marketgoo

Resell our SEO tools to help your customers succeed online with improved traffic and search rankings!