How to Scale Existing Apps with a Framework-Agnostic Design System
Learn how to build and implement a framework-agnostic, tech-agnostic design system for an existing web application to future-proof your frontend architecture.
⚡ TL;DR
A design system is often described as a collection of reusable components, design tokens, documentation, and guidelines.
That definition is correct — but incomplete.
When you inherit an existing web application, the hardest part of building a design system isn’t writing the first Button component or creating a colors.css file.
The hard part is discovering what the product already believes about design.
An existing application usually contains years of accumulated decisions:
- slightly different shades of the same color
- multiple spacing values
- several button styles
- inconsistent border radii
- different typography treatments
- duplicated components
- responsive behavior that evolved organically
- accessibility gaps
- one-off exceptions that nobody remembers creating
Your job is not to immediately replace all of that.
Your first job is to understand it.
This article presents a technology-independent framework for transforming an existing web application into a coherent, scalable design system.
What Are We Actually Building?
Before starting, it helps to distinguish three related concepts.
Design language
The visual and emotional character of the product.
It answers:
What should this product feel like?
For example:
Warm editorial professionalism.
That might lead to:
- strong typography
- generous whitespace
- dark navy structure
- warm accent colors
- restrained decoration
- paper-like surfaces
Design system
The broader system of reusable design decisions, components, patterns, rules, and documentation.
It answers:
How should we consistently design and build experiences?
Component library
The implementation of reusable UI components.
It answers:
How do we encode those decisions in code?
A design system can therefore be thought of as:
Design intent + design decisions + reusable patterns + implementation + documentation + governance
The component library is only one part of it.
The Framework
For an existing application, use this sequence:
Understand
↓
Audit
↓
Inventory
↓
Find patterns
↓
Define foundations
↓
Extract tokens
↓
Establish semantics
↓
Build primitives
↓
Build components
↓
Build patterns
↓
Validate
↓
Document
↓
Govern
↓
Migrate incrementallyThe important thing is the order.
Don’t start by building components.
Phase 1: Understand the Product
Before touching CSS, understand the product.
A design system exists to help a product serve its users.
So begin with three questions.
1. Who are the users?
Identify the primary users and their context.
For example, a resume website might serve:
- recruiters
- hiring managers
- collaborators
An enterprise dashboard might serve:
- administrators
- analysts
- operators
A consumer application might serve:
- first-time users
- returning users
- power users
The answer influences your design decisions.
2. What do users need to accomplish?
Identify the primary tasks.
For example:
Resume website
→ Understand who I am
→ Scan experience
→ Evaluate skills
→ Review projects
→ Contact meThis tells you what deserves visual priority.
3. What should the experience feel like?
Choose a small number of adjectives.
For example:
- credible
- thoughtful
- warm
- focused
- memorable
Avoid trying to make the product:
luxurious + playful + futuristic + nostalgic + utilitarian
A design direction becomes difficult to implement when it tries to communicate everything simultaneously.
Phase 2: Establish the Design Direction
Design direction translates product intent into visual language.
For example:
Warm editorial professionalism: a refined, content-first experience using expressive typography, dark structural colors, warm accents, generous whitespace, and restrained decoration.
Now translate each adjective into possible design decisions.
Adjective -> Design Decisions
Credible -> Strong hierarchy, readable typography, restrained colors
Thoughtful -> Editorial typography, generous whitespace
Warm -> Cream surfaces, warm accent
Focused -> Clear grouping, limited decoration
Memorable -> Distinctive headings or accent treatmentThis gives you a design hypothesis.
For example:
If we use editorial typography, generous spacing, dark navy structure, and a warm orange accent, the experience should feel thoughtful and credible.
That hypothesis can later be tested against the actual interface.
Phase 3: Perform a Visual Audit
Now inspect the existing application.
Do not redesign yet.
Your objective is observation.
Walk through the major pages and record what exists.
Look for:
- typography
- colors
- spacing
- buttons
- inputs
- cards
- navigation
- tables
- dialogs
- alerts
- badges
- icons
- images
- layouts
- responsive behavior
- interaction states
Think of this as archaeology.
You are discovering the design decisions that already exist.
Phase 4: Create a Visual Inventory
A visual inventory is a factual record of the current interface.
It answers:
What visual decisions exist, where are they used, and how consistently are they used?
For every significant surface, record:
- purpose
- size
- spacing
- color
- typography
- shape
- layout
- responsive behavior
- interaction states
For example:
Surface: Card
Purpose
Groups one project, experience, or educational item.
Current implementations
.card
.profile-card
.project-card
.experience-cardBackground
rgba(255, 255, 255, 0.78)Border
1px subtle navy borderAccent
4px orange left borderRadius
18pxPadding
1.4rem 1.35remShadow
0 14px 35px rgba(20, 33, 61, 0.06)The important point is that you are recording reality.
You are not yet deciding what the values should be.
Phase 5: Identify Repetition
Repetition is where design-system opportunities begin to emerge.
Suppose your inventory reveals:
Card A → 18px radius
Card B → 18px radius
Card C → 16px radius
Card D → 18px radiusYou have discovered a potential common decision.
Or:
Section A → 48px gap
Section B → 52px gap
Section C → 48px gap
Section D → 64px gapYou may discover that the application is approximately following a spacing rhythm.
The goal isn’t to force everything into a mathematical system.
The goal is to ask:
Which decisions are intentional enough and repeated enough to become system-level decisions?
Phase 6: Identify Inconsistencies
A design system shouldn’t only document consistency.
It should expose inconsistency.
For example:
Primary button
→ #E87532
Another primary button
→ #E66A27
Another CTA
→ #F0803COr:
Input radius → 8px
Card radius → 18px
Modal radius → 12px
Button radius → 10pxThese differences might be intentional.
Or they might simply be historical accidents.
Your job is to determine which is which.
Get Naga Sathya Bharadwaja Dandibhotla’s stories in your inbox
Join Medium for free to get updates from this writer.
This is an important mindset:
Difference does not automatically mean inconsistency.
Sometimes two values are different because they represent different semantic roles.
Phase 7: Discover Relationships
Values become meaningful through relationships.
Instead of looking at:
4px
8px
12px
16px
24px
32px
48pxlook for the underlying rhythm.
You might discover:
4px → 8px → 12px → 16px → 24px → 32px → 48pxThat suggests a spacing system.
The same idea applies to:
Typography
12px
14px
16px
20px
24px
32px
48pxBorder radius
4px
8px
12px
16pxContainer widths
640px
768px
960px
1200pxYou are looking for relationships rather than isolated numbers.
Phase 8: Establish Foundations
Once the inventory is understood, define the foundational design decisions.
Typical foundations include:
Color
Typography
Spacing
Sizing
Grid
Layout
Breakpoints
Border
Radius
Elevation
Motion
Iconography
AccessibilityNot every product needs every category.
Start with what the product actually needs.
Phase 9: Extract Design Tokens
Now you can begin converting repeated decisions into tokens.
For example:
:root {
--color-navy-900: ...;
--color-navy-700: ...;
--color-orange-500: ...;
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-3: 0.75rem;
--space-4: 1rem;
--space-5: 1.5rem;
--space-6: 2rem;
--space-7: 3rem;
--space-8: 4rem;
}But there is an important distinction.
A raw value describes what something is.
A semantic token describes why it exists.
For example:
--orange-500is a raw/color token.
Whereas:
--color-action-primarycommunicates its purpose.
This distinction becomes increasingly important as the system grows.
Phase 10: Separate Primitive and Semantic Tokens
A useful model is:
Primitive tokens
↓
Semantic tokens
↓
Component tokensFor example:
--color-orange-500: #...;
--color-action-primary: var(--color-orange-500);
--button-primary-background:
var(--color-action-primary);This creates layers of abstraction.
If the brand orange changes, you can change the primitive.
If the meaning of primary action changes, you can change the semantic mapping.
If only buttons need a special treatment, you can adjust the component-level decision.
Phase 11: Define Layout Rules
Now establish the structural system.
A container might begin with:
.container {
width: min(100% - 3rem, 1120px);
margin-inline: auto;
}But don’t blindly copy a number from another design system.
Ask:
- How wide is the content?
- How long should text lines be?
- Do cards need more width?
- How much breathing room does the design need?
- What happens on smaller screens?
The correct container width is a design decision derived from content and layout requirements.
Phase 12: Define Responsive Behavior
Don’t start with:
mobile
tablet
desktopStart with:
When does the design stop working?
Resize the interface.
Look for failure points:
Header becomes crowded
↓
Navigation wraps
↓
Card metadata collides
↓
Buttons become cramped
↓
Text becomes difficult to scanThe point where the layout fails is evidence for a breakpoint.
For example:
@media (max-width: 720px) {
...
}The breakpoint is therefore derived from the interface — not from a device marketing category.
Phase 13: Build Primitives
Now begin implementation.
Start with small primitives.
Examples:
Box
Stack
Inline
Container
Text
Heading
Icon
Divider
Button
LinkThe exact names don’t matter.
The principle does:
Build reusable primitives around recurring design decisions.
Phase 14: Build Components
Once primitives are stable, build higher-level components.
For example:
Button
Input
Select
Card
Badge
Alert
Navigation
Modal
TooltipEach component should encode:
- structure
- visual behavior
- states
- accessibility behavior
- responsive behavior
- token usage
A Button isn’t merely:
<button>Save</button>It also needs to define states such as:
default
hover
focus
active
disabled
loadingPhase 15: Build Patterns
Components solve individual UI problems.
Patterns solve recurring user-interface problems.
For example:
Search + filters + resultsmight combine:
Input
Select
Button
Badge
Card
Paginationinto a reusable interaction pattern.
This is where a design system starts becoming more than a component library.
Phase 16: Validate Against Real Screens
Don’t validate components in isolation only.
Put them back into real pages.
Ask:
Visual
Does the interface feel coherent?
Functional
Does the component behave correctly?
Responsive
Does it survive different viewport sizes?
Accessibility
Can it be used with:
- keyboard
- screen readers
- zoom
- reduced motion
- different contrast conditions?
Content
What happens with:
- long names?
- missing images?
- large numbers?
- translated text?
- empty states?
- errors?
Real content exposes weaknesses that isolated component demos often hide.
Phase 17: Document the System
Documentation should answer:
When should I use this?
Not simply:
What properties does this component have?
For a Button, document:
Purpose
When to use
When not to use
Variants
States
Accessibility
Examples
Content guidanceFor tokens, explain their meaning.
For patterns, explain the user problem they solve.
Good documentation reduces decision-making effort.
Phase 18: Migrate Incrementally
Do not attempt to rewrite the entire application.
Instead:
Existing application
↓
Inventory
↓
Tokenize one area
↓
Build components
↓
Migrate one feature
↓
Validate
↓
RepeatThis reduces risk and lets the design system evolve based on real usage.
A design system that nobody uses is not a successful design system.
Phase 19: Establish Governance
Eventually, questions will arise:
Should we add another button variant?
Should this spacing value become a token?
Should we create a new component?
When is an exception justified?
You need rules.
For example:
Add a new component when
- the interaction repeats
- the visual behavior repeats
- accessibility behavior needs to be standardized
- multiple teams need the same pattern
Don’t add a component when
- it is used once
- abstraction makes the implementation harder
- the differences between instances are greater than the similarities
This prevents the design system from becoming an abstraction factory.
The Complete Existing-App Workflow
The entire process can be summarized as:
1. Understand users
2. Understand product goals
3. Define design direction
4. Audit existing interfaces
5. Create visual inventory
6. Identify repetition
7. Identify inconsistencies
8. Discover relationships
9. Define foundations
10. Extract primitive tokens
11. Define semantic tokens
12. Establish layout rules
13. Establish responsive rules
14. Build primitives
15. Build components
16. Build patterns
17. Validate against real pages
18. Document
19. Migrate incrementally
20. Govern and evolveThe Most Important Principle
When building a design system for an existing application:
Don’t start by asking, “What components should I build?”
Start by asking:
“What design decisions already exist, why do they exist, and which of them should become shared decisions?”
That change in perspective is fundamental.
You’re not simply converting CSS into components.
You’re turning an accumulated collection of UI decisions into a coherent system.
The transformation is:
Existing UI
↓
Observation
↓
Inventory
↓
Patterns
↓
Design decisions
↓
Tokens
↓
Components
↓
Patterns
↓
SystemAnd that is the real process of extracting a design system from an existing product.









