Jan 11, 2026
Design Systems Under Real Constraints
When I joined a growing SaaS team, I did not walk into a clean frontend foundation or a clearly defined UI strategy. What I inherited was a partially built application, inconsistent styling patterns, undocumented decisions, and a codebase that felt out of sync with how modern design systems are meant to function.
The application was built on Next.js, with React forming the underlying component model. In practice, React surfaced primarily through a small set of framework components rather than a cohesive component system. Styling lived in multiple layers. MUI was used selectively for pre built elements like dialogs and flyouts, while much of the interface relied on custom layouts and styles. That mix made it difficult to enforce consistency through abstractions alone. Design decisions existed visually in Figma, but had no reliable representation in code.
I did not have full control over the early tech stack decisions that led there. That reality is common, especially in fast moving startups. What mattered was finding a way forward that improved consistency without breaking velocity, trust, or the product itself.
What Should Have Happened
In an ideal scenario, design system work begins before large scale component implementation. Tokens are defined early. A theming layer is wired intentionally. UI frameworks are either fully adopted or consciously avoided. Designers and engineers share a single source of truth for spacing, color, typography, and state.
That is the clean path.
It was not the path available.
Instead of resetting the stack or forcing a rewrite, the focus shifted to introducing order incrementally. The goal was not theoretical perfection. It was consistency, predictability, and long term maintainability inside an existing Next.js and React application.
Establishing a Token Driven Foundation
The first step was implementing a token based design system that could live alongside existing components without causing regressions. A centralized token file was created to represent color, typography, spacing, borders, and elevation. These tokens were aligned directly with Figma variables to reduce ambiguity and eliminate interpretation gaps.
As the system evolved, the direction shifted toward custom HTML based components rather than relying heavily on framework abstractions. That choice made it possible to apply tokens consistently through a single, centralized CSS layer, while still allowing React components to remain lightweight and composable.
Rather than relying on ad hoc styles, components began consuming shared values directly. Even when legacy components were still present, their surrounding layout, spacing, and visual rhythm started to feel intentional.
This work extended beyond visual styling. It required understanding how React components are composed, how styles cascade across a Next.js application, and how specificity and injection order affect long term scalability. Those considerations shaped both the decision to centralize styling and how the system was introduced over time.
Working Inside an Imperfect Framework Setup
Part of the complexity came from understanding how the application had been assembled. Next.js handled routing, rendering, and overall structure, while MUI had been introduced early to accelerate development through pre built components and theming.
In practice, that theming layer was never fully wired into the application. MUI defaults, custom CSS, and emerging design tokens all existed at the same time, without a clear hierarchy. Overrides accumulated. Specificity issues became common. Visual inconsistencies were easy to introduce and difficult to reason about.
Rather than removing MUI or forcing alignment all at once, time was spent understanding how its theming system was intended to function within a Next.js and React environment. That included how styles were injected, how component overrides worked, and where conflicts originated.
Over time, it became clear that leaning more heavily on custom HTML elements provided greater control over styling, composition, and token application. That shift reduced reliance on framework overrides and made the system easier to reason about as it grew.
In some cases, tokens flowed directly into custom React components. In others, MUI components were adapted to respect shared values. The goal was not to eliminate tooling. It was to make the system predictable.
This kind of work rarely appears in tutorials. It surfaces when working inside real production systems.
Designing for Implementation
Throughout this process, design and engineering were tightly coupled. Components were designed in Figma, mapped to React implementations, reviewed against real data states, and iterated based on constraints discovered in code.
That feedback loop mattered. Design decisions were informed by how components behaved in practice. Engineering decisions were grounded in design intent. Over time, this reduced friction across the team and increased confidence in the system being built.
Systems Under Real Constraints
Most production frontend systems are not built under ideal conditions. They evolve under deadlines, partial decisions, and shifting ownership. Frameworks like Next.js and React provide structure, but they do not guarantee consistency. UI frameworks can accelerate development, but only when they are intentionally integrated.
In those environments, success depends less on choosing the perfect architecture and more on understanding the one that already exists. Introducing consistency requires sequencing, compromise, and an awareness of how changes affect a live product.
This kind of work sits between design and engineering. It is less about creating something new and more about creating alignment. Over time, that alignment reduces friction, increases confidence, and allows teams to move faster without accumulating more inconsistency.
That is the context this system was built in, and it reflects how most modern frontend work actually unfolds.