How a frozen migration and four competing button implementations became a unified system across three products — built through continuous, verifiable progress instead of another big-bang refactor.
When I joined Reteach, the Vue-2-to-3 migration had been frozen for months. In practice, the UI layer was fragmented: four different button implementations, each created as a workaround for Bootstrap’s limits. Nobody wanted to touch that codebase because the Bootstrap-Vue library was abandoned upstream and every change risked breaking something. A previous attempt at a full redesign had failed; trust in large-scale refactoring was low.
We agreed early that another big-bang refactor would only repeat the problem. Instead, we aimed for continuous progress that could be proven step by step. The question was not how to rebuild everything, but where to start so that the next improvement would become easier rather than harder.
Main navigation showing the untokenised layout
New tokenised admin app with colors compliant with accessibility standards and brand guidelines
Token Foundation
The first decision was to establish a token foundation. Colors, typography, and spacing had been defined inconsistently across the three Reteach products. Functional colors replaced the scattered brand palettes, and semantic naming connected Tailwind’s visual logic to our own variable system. The similarity to Tailwind class names initially caused confusion — a token like --color-warning-500 looked identical to a Tailwind class but wasn’t — which cost roughly two weeks of corrections. Once naming was clarified, design and engineering could finally use the same vocabulary, and implementation friction dropped noticeably.
First we checked the current primary button color — only used for the primary button, not in marketing or as a secondary color. The brand color didn't perform well on WCAG ratings, so we settled on a darker tone for primary app actions.
A simple variant setup in Figma to check the overall appearance of the various color setups and combinations with the new color scale.
Setup of primary color tokens
Token consumption flow
UX Improvements
The token layer then became the base for addressing the two largest UX pain points identified through a support-ticket audit: table inconsistencies and the excessive use of modal dialogs. Tables had diverged in markup and behaviour; modals were used for nearly every interaction and blocked workflows. We built new atomic table components and replaced modal dialogs with a lighter drawer pattern that kept users in context. After rollout, a frontend engineer summarised the difference: “I can now estimate how long it takes to develop a modal pattern.” Feature estimates became reliable again because developers could scope work by component rather than by guesswork.
While the brand, primary, and secondary colors were being unified and functional colors started to be consistently applied…
…the long-term vision was already in the making: functional colors became more explicit, allowing for a more OS-like feel and an agnostic color system covering custom themes and dark themes.
Modals had issues, especially with larger configurations
We solved this by introducing the drawer pattern
Designed a new Layout Frame, Header and Sidebar to steer focus on each page to the one most important action
New table design allowed for horizontal scrolling and display of as many columns as needed. Tables were often restricted by their own width before.
Storybook as Shared Reference
To document and stabilise these components, we introduced Storybook as a single shared reference. The goal was not documentation in the traditional sense, but an environment where design, development, and product could check the same artefact. Designers could show variants directly, engineers could test states in isolation, and product managers could review scope without waiting for deployments. The component lifecycle stayed intentionally simple — Candidate, Implemented, Deprecated — which kept maintenance manageable. Review loops shortened, and discussions shifted from whether something existed to how it should behave.
A clear before image showing the clash of naming paradigms: 'btn' vs 'button', and different approaches to passing text or behaviour as props. We not only unified terminology but used the refactor to develop clear frontend conventions.
Grown Storybook — organically expanded without conventions
Storybook with introduced naming conventions and documented tokens
System Expansion and Automation
Over time, the system expanded across the Marketing Website, the Client Academies, and the Client Admin Panel. Consistency became a question of shared behaviour rather than visual uniformity. When an issue appeared, we applied the Five Whys method to trace it back to the responsible component, fixed it once, and propagated the solution through all products. That process turned debugging into a source of learning.
For synchronisation across tools, we automated the pipeline between Notion, Figma, Storybook, and Git version control using Claude Code MCPs. This eliminated manual copy errors and ensured that documentation and implementation stayed aligned. Builds became faster and releases more predictable because information moved through automation rather than meetings.
The app as I found it when joining Reteach
Final design — this change happened entirely by introducing conventions and changing values, without any explicit refactor for the design system
Early on, some stakeholders questioned the investment. One C-level comment was: “You’re just making it prettier.” Since Reteach had no established monitoring or data-driven practice, we relied on informal proxies — support-ticket trends, onboarding duration, estimation reliability — to make progress visible. Over several release cycles the discussion gradually shifted from aesthetics to performance.
In retrospect, the decisive factor was not technology but method. Tokens reduced decision overhead, Storybook reduced assumptions, and shared ownership reduced friction. The system now holds across three products, and new components follow the same lifecycle. Evolution proved more effective than ambition when outcomes had to be delivered.