Meltwater is a social media intelligence platform where teams create, publish, and analyze content across many social accounts. The product is not a single app. It is a suite of products, and each product was owned by a different team.
Over time, each of those teams had built its own frontend in its own stack. The same building blocks, buttons, dropdowns, modals, inputs, and other common UI, existed in several places, written again for each product. There was no shared source for any of it.
This caused two problems. The UI looked and behaved differently from one product to another, and it was hard to keep standards consistent. Every component was tightly coupled to the product it lived in, so a fix or a design change had to be repeated everywhere, which added up to a lot of duplicated effort and tech debt.
We decided to build one shared library that every product team could use, no matter which framework their product was written in. To make that possible, we built the components as Web Components using Stencil.js, so they could run inside any of the existing apps without forcing a rewrite or a common framework.
Each product consumed the library in two steps. First the component bundle was loaded into the app, and then the components were registered as custom elements before they could be used on a page. This kept the integration predictable across very different products.
The most important design decision was to keep the library loosely coupled. We relied heavily on slots instead of props, so consuming teams composed the UI they needed and we kept business logic out of the components. Components stayed presentational and did not carry any product-specific assumptions.
For anything interactive, components communicated through emitted events rather than callbacks passed in as props. This gave each team the freedom to decide what happens on their side, and it kept us from baking tight business logic into the shared layer.
The same components composed with slots across different product teams.
Documented every component and its variants in Storybook.
On the release side, we published the packages with semantic versioning so teams could see exactly what changed between updates and upgrade safely. The components were published to an internal registry as well as the public npm registry, which made both installation and updates consistent for every team.
We documented the whole system in Storybook so teams could browse components, see their variants, and understand how to use them without reading the source. To keep quality high as the library grew, we backed changes with unit tests and used Chromatic for visual regression checks, so an accidental UI change was caught before it reached a product.
Teams stopped rebuilding the same components in parallel. New pages looked and behaved consistently even when the underlying products were built on different stacks, and the design standards were finally shared instead of copied.
The loose coupling paid off in maintenance. Because components held little business logic and communicated through events, fixes and improvements landed once and rolled out to every product through versioned releases instead of repeated one-off patches.
This reduced the frontend tech debt across the suite and made it faster for teams to build new features on top of a reliable, well-documented base.
Web Components built with Stencil.js, published via npm, and integrated across Vue-based product surfaces.
OR
Write To Us At Your Own Convenience