Musixmatch Blog

Enhancing the experience of music worldwide.

Meet Ritmo, Musixmatch’s cross-platform design system

Andrea Zilibotti
Musixmatch Blog
Published in
9 min readApr 23, 2024

--

When Musixmatch initially embarked on its music and tech industry journey, it established itself primarily as a music player allowing users to enjoy their favorite songs alongside time-synced lyrics. Over the years, our focus has been on enhancing the music listening experience, crafting the most intuitive user interfaces for our iOS and Android apps. Through this effort, we have successfully built a diverse community of millions of music enthusiasts around the world.

However, we have since gone beyond lyrics engaging new types of users, such as music creators and podcasters. This expansion has made it necessary to create new apps and tools tailored for them, that could be easily accessed from any device.

It is this ever-changing scenario that’s grown the necessity to create a design system to scale the user interfaces we work on every day: we called it Ritmo (if you don’t know it means rhythm in Italian, and you can imagine why we chose this name) and after more than four years it’s still empowering all our products.

Logo for Ritmo, the Musixmatch’s design system
Logo for Ritmo, the Musixmatch’s design system

Our approach

One of the most interesting aspects of working on design systems is that there is no absolute truth for everyone: each team or organization finds its own, based on its own needs and those of the people who are part of it. The human part, which consists in the willingness to work with a system made of constraints that we ourselves design, is no less important than the more technical part of “how to build it”.

One source, multiple platforms

Following these important considerations, as well as our need to keep the user experience and identity coherent across multiple apps and platforms, we’ve started to radically change the way we design our products by focusing more on the experience itself, rather than creating it ad-hoc for each platform. Ritmo played a key role in this new challenge for us, because we built it based on the same concept: defining cross-platform standards and components for both designers and developers.

Now, if you’re not very familiar with this topic, you’re probably wondering:

What does “cross-platform” really mean?

With the term “cross-platform” we mean something built with a single codebase which looks and performs the same on all the platforms we want to support (Web, iOS and Android in our case).

Although it may sound the same as what other design systems like Material Design already do, we should differentiate those cases and call them multi-platform design systems instead, because the visual appearance and implementation of components may be different from platform to platform (a few years ago Danny Banks wrote a very interesting article about this difference, be sure to check it out if you want to go deeper into this topic).

Differences between “multi-platform” and “cross-platform” approaches to design systems
Differences between “multi-platform” and “cross-platform” approaches to design systems

As you can see in the image above, the two approaches differ mainly in the number of libraries that need to be created and maintained. If your design team uses Figma, they will likely have a library of components for each platform, if only to differentiate some specific system components like navigation bars. And even if this is not the case, the codebase will certainly be different, because the languages and frameworks used for the development are different. While you can maintain visual consistency of foundations like colors or typography by simply syncing a single source of design tokens across all platforms using tools like Style Dictionary, having components implemented differently requires more maintenance in the long run.

A cross-platform design system, on the other hand, requires nothing more than a couple of libraries, one for designers and one for developers, with the latter being the only “real” source of truth for products. To achieve this goal it’s necessary to generalize the user experience, simplifying it as much as possible and making it coherent regardless of the context, defining paradigms and rules for how components should adapt.

An example of how to simplify the app navigation across different platforms and screen sizes
Our header navigation (based on just two levels, home and internal pages) is an example of how to simplify the UX across all platforms

Creating a cross-platform ecosystem

If our objective is to develop once for all platforms, the differences between major programming languages like JavaScript, Java/Kotlin, and Objective-C/Swift make this a complex task. Before beginning to build our design system, we must select the appropriate cross-platform frameworks to incorporate into our front-end tech stack. Fortunately, due to growing demand and popularity among developers, we have a few options available to choose from.

One in particular, called React Native, originally developed by Meta and then open-sourced in 2015, was one of the first to propose a cross-platform approach to native mobile app development. From a technical standpoint, React Native allows you to write React code (in JavaScript) which renders to multiple native platforms, acting as an interface between JavaScript and native UI frameworks.

React Native doesn’t create new UI paradigms, but simply maps your custom React components to real Android and iOS ones, allowing developers to start from a set of core building blocks. Thanks to this aspect, when applied to design systems, React Native becomes a very powerful tool, providing a good compromise between flexibility and consistency with native UI.

Connecting all the dots

While React Native’s motto is “Learn once, write anywhere”, we tried taking it a step further and made a bet on writing once and deploying everywhere, also including web platforms as our target. We’re happy to see that a large part of the React Native community is moving towards this direction lately, where more and more open-source projects like Expo, Tamagui or Meta’s new React Strict DOM are emerging.

At the time, to kick off our new ecosystem our choice was to use React Native for Web, which takes React Native components and renders them on browsers. It is like a “compatibility layer” which allows us to achieve our goal, creating a unified solution for the development.

How React Native and React Native for Web are connected to make our JavaScript code work on web and native platforms
How React Native and React Native for Web are connected to make our JavaScript code work on web and native platforms

Crafting Ritmo components

This ecosystem is the perfect base for implementing our design system but most of the work starts with the design phase, defining all the specs we need on Figma which are collected in the Ritmo design library.

We spend time creating them by thinking about how they will be implemented in the code, trying to maintain consistency and platform-agnosticism in name structure, properties and variants. Also, by choosing the right defaults for all of them, we can cover the most common use cases and speed up the work of both the designer and the developer.

An example of API consistency between design and code
An example of API consistency between design and code

This type of work is certainly easier for simpler components such as buttons, avatars or input fields, which are usually used standalone. However, it becomes essential for a cross-platform design system to also define the behavior of more complex components such as those that influence app navigation, because the experience will be the same everywhere.

The component swap

Let’s talk about the dialog component, for example. It can be both informative or alert, and on large screens, it’s displayed classically with a close button at the top. On small screens, however, it’s automatically replaced by a bottom sheet, which is a separate component within Ritmo but mainly used for these cases. What therefore occurs is a component swap between two different instances, which maintain their independence and the possibility of being modified, with the aim of making the dialog more usable based on the size of the viewport.

In fact, using a bottom sheet in that case allows us to:

  • Place the actions at the bottom in the so-called “thumb zone”, in other words more reachable for users on mobile devices
  • Use a dragger to dismiss it, a standard behavior especially in the mobile apps we use every day
How our dialog component turns into a bottom sheet on small screens
1/2 — How our dialog component turns into a bottom sheet on small screens
The swap works behind the scenes, leaving the Dialog’s usage easy to use in the project
2/2 — The swap works behind the scenes, leaving the Dialog’s usage easy to use in the project

This is just an example, but we also use component swaps for dropdown menus, lists or grids. Both designers and engineers, thanks to our guidelines, know these paradigms and do not have to wonder how each component will appear in a specific context. This approach allows us to focus even more on the product and accelerate its implementation, since we only have to design how the page content adapts to different screen sizes, regardless of whether it’s part of a native app or a website.

Design specs define the behavior of the Carousel on different screen sizes, which can be selected as a component variant
Design specs define the behavior of the Carousel on different screen sizes, which can be selected as a component variant

Learning along the way

Since the first Ritmo-based product was released more than four years ago, our design system has continually evolved into today’s mature version. This doesn’t mean we are “at the end”, simply because as we know design systems always live and evolve. Along the way, though, we have learned many things that we can share.

When following the cross-platform approach, the concept of design language consistency is heavily emphasized compared to other design systems. The benefits are tangible, especially because users always feel “at home” when using one of our products.

On lyrics pages the interface is almost always the same across different devices
It doesn’t matter from which device users navigate: as in our lyrics page, the interface is almost always the same

Another key aspect is the possibility for all our designers and engineers to work on any of the company’s products. With a cross-platform design system like Ritmo, people share the same knowledge every day and can work interchangeably on different projects, reducing technical debt.

This means that if you are a designer or developer, for example, you don’t necessarily need strong iOS and Android skills to create a native app using Ritmo.

The contribution

At Musixmatch we encourage everyone to take initiatives to improve the projects we work on, especially for the design system since it’s shared and we use it every day. Ritmo has a few owners, each one with a specific area of expertise, who also act as advocates and reviewers of all contributions provided by designers and developers working on other products.

This process has the advantage of being driven by product priorities and ensuring that everyone feels part of the system by adding their own bricks, as if we were working on an internal open source project.

The contribution process to Ritmo is open to both owners and non-owners
Everyone contributes to Ritmo, both owners and non-owners

The costs

However, as for everything, there are also some downsides. Since one code fits all, applying changes to these components takes longer because regressions can occur anywhere and it is mandatory to perform proper tests that cover every platform.

In addition, we need to pay close attention to web performance and accessibility. Fortunately, the React Native team and the large community behind it are doing an incredible job in these areas, increasingly reducing the differences with web and native code development on all platforms. Ritmo, having been built on top of these technologies, receives all these updates and adds its own part to the cause, such as improving support for SSR components.

Looking forward to new challenges

As mentioned at the beginning of this article, regardless of how you decide to create a design system, the most important thing is to always listen to the needs of the people. Their skills, the team size, and the company’s product offerings are all variables that led us to choose a way to iterate faster and deliver products everywhere. But this is our truth, it doesn’t mean it can necessarily work for you too.

That being said, new challenges are always around the corner. One of our main goals at Musixmatch is to make our content more accessible to the rest of the world. This could involve creating a “more vocal, less touch” user experience or making our interfaces easier to use for individuals with disabilities. Either way, Ritmo will continue to lead us on this stage, and continue to evolve as it has in these years.

If after reading this story you are curious about playing with Ritmo, take a look at Musixmatch’s open positions and get ready to join our band! 🎸🙌

--

--

Andrea Zilibotti
Andrea Zilibotti

Written by Andrea Zilibotti

Senior UX Engineer @Musixmatch. Passionate about modular design and systems.

No responses yet