dhruvaldarji — portfolio
projects

2017 – 2021 · Senior Software Engineer · 6 min read

Enterprise Design System

Angular CDK component library, rebrandable design-token layer, and federated governance model that reached 150+ codebases at OneTrust, including a 50-app micro-frontend platform, 70 reusable libraries, and branded products that shipped on customized token overrides. Designers mocked against one source of truth, and the Figma-to-shipped gap narrowed to what teams had deliberately customized.

  • Angular CDK
  • TypeScript
  • Design Tokens
  • Storybook

A single OneTrust admin session could cross four products that looked and behaved like four different vendors. I built the fix as three things: an Angular CDK component library, a rebrandable design-token layer, and a federated governance model that together reached 150+ codebases: roughly 50 micro-frontend sub-applications, 70 reusable libraries, and a tail of branded products shipping on customized token overrides. Accessibility and visual-regression defects dropped once product teams adopted the system, and the micro-frontend shell pulled adoption in at the seams where product surfaces met the platform.

The problem

OneTrust grew through acquisition, and the UI surface grew with it. By the time the design system shipped, the frontend estate spanned 150+ codebases: roughly 50 micro-frontend sub-applications assembled into the admin and consumer shells, 70 reusable libraries shared across those apps, and a tail of acquired or externally branded products sitting alongside the core portfolio. Each acquired product arrived with its own UI conventions, color values, spacing, and interaction patterns. The customer experience fragmented at every seam. Product engineers, designers, acquired-product integration teams, and the platform and shell teams hosting them all paid the tax.

Teams had rebuilt every primitive from scratch, which was expensive but survivable. The deeper cost was the missing theming layer and the missing UI contract. Colors, spacing, typography, and interaction conventions lived inside each codebase as literals, so a rebrand, a dark mode, an accessibility fix, or a simple brand adjustment had to be made across 150+ codebases, by dozens of teams, on dozens of schedules.

The approach

I shipped it as three layers, in that order:

  1. Design tokens first. Tokens defined color, spacing, typography, radius, and motion as the single source of truth. They were shaped for mono-brand delivery and sized for rebrandability, so a future palette swap, a dark mode, or an acquired-product skin could drop in without anyone touching component source. A handful of branded products did exactly that, shipping under their own identity via customized token overrides while consuming the unchanged component library underneath. Rebrandability was load-bearing here, and those branded products are the proof it held.
  2. Components on Angular CDK, compound and slot-based. The system exposed compound components with projection slots: a Dialog with DialogHeader, DialogBody, DialogFooter; a Menu with structured slots for trigger, list, and items. Consumers assembled UI from parts, which beat both the monolithic styled component and the pure headless primitive for this estate. Angular CDK supplied the accessibility and interaction primitives underneath.
  3. Governance as the third product layer. A core team owned direction and reviewed every change; product teams contributed through a defined RFC and PR path. Breaking changes moved through an RFC, shipped under SemVer with deprecation cycles, and, where the change warranted it, ran as a parallel API alongside the old one until telemetry showed usage had fallen to near zero.

Distribution was deliberate. The micro-frontend shell required DS-rendered chrome (header, navigation, modal portal), which pulled every remote into the system at the boundary. Beyond the shell, product teams adopted because the compound API was faster to build against than their existing primitives. The shell contract forced the boundary and the faster API did the rest. We never had to ask an executive to mandate it.

The outcome

Accessibility and visual-regression defects dropped once product teams consumed DS components. One keyboard-navigation fix or one color-contrast fix in the core reached every surface using that component, where before it meant a parallel PR in every consuming codebase. Designers had one source of truth to mock against, and the gap between Figma and shipped UI narrowed to the parts teams had consciously customized.

The shell became the most consistent surface at OneTrust first, because it was the one place adoption was forced by contract. Surfaces behind the shell followed at the pace their teams chose. The system stayed small enough to govern because federation pushed authoring out to product teams while the core retained the review gate.

A design system is a product. Take that seriously and every subsequent decision changes: it has consumers with their own roadmaps, it has a roadmap of its own instead of a launch date, and it owes those consumers an SLA around breaking changes. The teams I have seen do this well plan for the second year. The ones that treat it as a launch end up with a library nobody maintains.

What I’d change

The concrete expression of that principle, in retrospect, was distribution. The system had tokens, components, governance, and a healthy RFC process. What it lacked, early enough, were migration codemods. Rewriting accumulated call sites across 150+ codebases was the slow grind that gated adoption at the long tail. Treat distribution as a first-class product surface from day one, ship codemods alongside every breaking change, and the adoption curve pulls forward by quarters.