Building components that adapt across product needs
Designing components that absorb product variation

At Deezer, Tempo exists without a fully dedicated Design System team, either on the design side or the engineering side. Component work has to fit between product needs, roadmap constraints, and the available capacity of designers and engineers.
This changes the way components are designed from the very beginning.
Problem
Product teams rarely need the exact same component twice. A component created for one feature often becomes relevant elsewhere, but with small differences in layout, content or behaviour.
When those variations have not been considered early enough, each new use case can require another component, a feature-specific variant, or a redesign of the original structure. In a system maintained alongside product work, that repetition quickly increases the number of components, variants, and behaviours the team has to maintain.
Starting from neutral building blocks
This approach also applies below the component level.
Whenever possible, components are assembled from small, shared building blocks that do not carry product-specific semantics. A structural element should not assume that it belongs to Settings, Search, a playlist, or any other particular feature when the same behaviour could be useful elsewhere.
Keeping these foundations semantically neutral makes them easier to combine across different product contexts. Product meaning is introduced through content and configuration rather than being embedded in the underlying structure.
This creates a more atomic system: shared elements can be reused to compose larger components, while the same layout, spacing, interaction, and accessibility decisions remain consistent across them.
Designing for likely variation
When a new component is needed, we cannot design only for the immediate use case. We need to anticipate the most likely variations early enough to avoid creating new Design System work every time a product team needs a slightly different version.
This means defining components with flexible properties from the start: with or without icon, leading or centered alignment, with or without action, single button or button group, different content densities, and other common variations.

The intent is not to predict every possible future request. It is to look beyond the first screen and identify which structural differences are likely to recur.
Building around composition
Slots are an important part of that approach. Some components are built mostly, or entirely, around slots so they can support multiple product contexts without requiring a new component each time.

Item List is a good example. It was initially created for Settings, but its structure also needed to support many variations: a chevron, toggle, radio button, checkbox, icon, metadata, or different trailing actions. By defining the component around interchangeable slots, the same base structure can absorb those variations while keeping a consistent layout and behaviour.
Knowing where to stop
The objective is not to make components infinitely configurable. Too much flexibility makes a system harder to understand, use, test, and maintain.
At Deezer, we managed this by defining preferred configurations based on patterns that were already used or strongly expected across the product. These defaults covered the most common cases and gave teams a clear, predictable path through the component.
The underlying properties remained accessible when a legitimate product need could not be met by those preferred configurations. Teams could adapt the component without immediately creating a new variant, but that flexibility was available to support a concrete need rather than encourage arbitrary customization.
The work was therefore not only to decide what a component could support, but also what it should present by default. The component API could remain broader than the set of configurations actively promoted in the library.
Outcome
This approach helped Tempo remain usable in a context where each new component request could otherwise become maintenance debt.
Components could support a broader range of product situations without multiplying feature-specific variants. Preferred configurations kept everyday use straightforward, while semantically neutral building blocks made the system more predictable to extend, implement, and maintain.