Introduction
Introduction

To comply with non-disclosure agreement, I have omitted and obfuscated confidential information in this case study. All information in this case study is my own and does not necessarily reflect the views & facts of the company.

To comply with non-disclosure agreement, I have omitted and obfuscated confidential information in this case study. All information in this case study is my own and does not necessarily reflect the views & facts of the company.

Challenge

Challenge

While working on the Passenger Sentiment Dashboard for an airline-focused analytics platform, I faced a challenge that went far beyond UI polish: the product needed to translate raw survey data into clear, actionable insights—fast. But more critically, the UI needed to be modular, scalable, and built to adapt as new feedback types, metrics, and use cases evolved.


The product team wanted to reduce analysis time, and the design had to support that shift without becoming brittle or inconsistent.

While working on the Passenger Sentiment Dashboard for an airline-focused analytics platform, I faced a challenge that went far beyond UI polish: the product needed to translate raw survey data into clear, actionable insights—fast. But more critically, the UI needed to be modular, scalable, and built to adapt as new feedback types, metrics, and use cases evolved.


The product team wanted to reduce analysis time, and the design had to support that shift without becoming brittle or inconsistent.

The System-Driven Solution

The System-Driven Solution

To meet this challenge, I built a fully tokenised, variable-based design system in Figma—one that supported every layer of the dashboard UI, from colours and spacing to inputs, controls, and data states. Each component was built with system logic in mind:

  • Semantic colour tokens for data states (positive, neutral, negative)

  • Number-scale-driven spacing for consistent layout rhythm

  • Input fields, dropdowns, buttons—all driven by component tokens

  • Scoping and naming conventions that made developer handoff effortless


This case study walks through how that system was architected—not as a design artefact, but as a thinking model: one that enabled fast decision-making, consistent evolution, and cross-functional clarity at scale.

To meet this challenge, I built a fully tokenised, variable-based design system in Figma—one that supported every layer of the dashboard UI, from colours and spacing to inputs, controls, and data states. Each component was built with system logic in mind:

  • Semantic colour tokens for data states (positive, neutral, negative)

  • Number-scale-driven spacing for consistent layout rhythm

  • Input fields, dropdowns, buttons—all driven by component tokens

  • Scoping and naming conventions that made developer handoff effortless


This case study walks through how that system was architected—not as a design artefact, but as a thinking model: one that enabled fast decision-making, consistent evolution, and cross-functional clarity at scale.

Duration

2 weeks

My Role

UX Designer

Contribution

Tokenised design system; UI components; Colour system; UX strategy; Token mapping; Documentation

Team

Data Analyst; Data Engineer; Product Owner

Colour system (using variables and tokens)

From base colours to semantic meaning across surfaces, borders, and text

After defining our base colour palette and grayscale system, the next step was to create semantic colour tokens—a bridge between raw values and component-level usage. These tokens enable designers and engineers to apply colours like surface/default or text/caption without needing to remember hex codes or visual intent.

Why this matters:
A semantic system unlocks scalability. It removes the guesswork and supports theming, dark mode, and cross-product consistency—while still being flexible enough to evolve.

Strategic Palette Design

Each colour was developed from a 500-level base, then extended with shade values up to 950 and down to 50. The grayscale includes subtle hue shifts to avoid visual flatness—critical in modern UIs.


All tokens are named using a predictable structure (Colour/Blue/700), and all base colours were prepped in variables—even if not in active use—so future themes or feature modules can tap into them without friction.

Semantic Tokens: Bridging Visuals to Meaning

Here, I shifted from base colours to meaningful, abstracted tokens. Instead of assigning hex codes directly to components, I defined roles like:

  • Surface/Default

  • Border/Disabled

  • Text/Negative


These reference the core palette behind the scenes (e.g. Greyscale/700, Red/600, etc.). This abstraction allows:

  • Global theming with minimal change effort

  • Clearer handoff for devs and design QA

  • Future-proofing: swapping Text/Body from dark grey to white becomes trivial in dark mode

Token Mapping in Action

Each colour family (e.g. Purple, Red) follows the same semantic mapping structure—ensuring consistency across interaction states and brand extensions. I applied the same logic across all UI layers:

  • Surface tokens for background containers

  • Border tokens for outlines and dividers

  • Text/Icon tokens for legibility, emphasis, and accessibility


This allowed for easy reuse, predictable interaction design, and contrast tuning at a semantic level.

UX Thinking Behind the System

A colour system isn't just a palette—it’s a contract between design and code, and a tool for UI clarity.


Here’s what made this system truly effective:

  • Predictable contrast ratios (especially across surface + text pairings)

  • Accessible defaults built into the semantic structure

  • Effortless design QA—tokens speak for themselves (Text/Caption or Border/Darker)

  • Theming readiness baked in from the beginning

Number Scale & Radius Tokens

Creating a universal sizing system that scales across layout, components, and interaction design

To support consistent and reusable component design, I established a number-based scale using Figma variables. The idea was simple: define a core set of primitive values and give them human-readable size labels (e.g. XS, M, 2XL) to reduce guesswork and support component logic later on.

Rather than choosing arbitrary pixel values, I mapped everything to this unified scale—from spacing and padding to width, height, and border radius. This means fewer inconsistencies, easier updates, and a system that scales with product complexity.

Number Scale

The number scale starts at 2 and extends up to 999:

  • Lower values (2–24) cover small-scale spacing and detail-level UI

  • Mid-range (32–40) works for containers, cards, and modular layouts

  • 999 ("Full") is reserved for stretch and full-width scenarios


Each step in the scale corresponds to tokens like 2XS, XS, M, 3XL, etc., allowing us to design with intent rather than pixels.

Applying Tokens to Radius

I then used the scale to create semantic corner radius tokens. Instead of defining custom corner values for every component, I assigned radius values like Radius/S, Radius/M, and Radius/Full.


This made it easier to:

  • Keep consistent rounding across buttons, inputs, and cards

  • Adjust radii system-wide from a single source of truth

  • Handle special cases (e.g. pills, circular avatars) with Radius/Full

Radius

XS

S

M

L

XL

Full

Extending the System: Padding & Layout

Padding, spacing, and layout constraints were also aligned to the same number tokens. This let me build clean, responsive components without constantly checking pixel values.

I scoped each token to its relevant use case in Figma (e.g. Gap, Corner radius, Text content, etc.), so designers only see relevant values based on context. That alone saved a ton of confusion and UI clutter.

This scoped approach allowed my team to work faster and more confidently—less scrolling through irrelevant tokens, more focus on structure and behaviour.

Key Insight: Design Systems Need Design Logic

When you're building a component library at scale, consistency isn’t just about the visuals—it’s about systemic thinking. This number scale system gave us:

  • A language to talk about spacing (“use M for default padding”)

  • A flexible structure that works across products and themes

  • A logic-driven foundation that scales from 1px tweaks to complex design handoff

Buttons: Tokenised, Responsive, and Built to Scale

Designing interactive components that are consistent, flexible, and easy to maintain

After building out the base colour system, number scale, and semantic tokens, I moved on to one of the most reused and critical components in any UI system: buttons.


Rather than treating buttons as isolated UI blocks, I approached them as token-driven templates—composed of interchangeable variables for size, padding, colours, and interaction states. This gave our team both visual consistency and practical agility.

Why Buttons Need to Be System-Smart

Buttons carry heavy responsibility. They guide action, convey hierarchy, and often set the tone for the rest of the product's UI. That’s why I engineered them around:

✳️ Component tokens – for structure (padding, icon size, radius)

🎨 Semantic colour tokens – for surface, border, and label text

🧩 Variants + properties – to cover states, sizes, and icons without redundancy


This setup ensures that every interaction is predictable, accessible, and easy to adapt—across screens, themes, or even different brands.

Component Tokens: Anatomy of a Button

Each button size (Small, Medium, Large) is defined through its own set of component tokens, including:

  • Radius – from Radius/S

  • Spacing – controlling gaps between text & icon

  • H-padding / V-padding – tokenised horizontal/vertical space

  • Full padding – used when applying padding uniformly

  • Icon Size – tied to the number scale


Rather than hardcoding these values in every variant, I linked each token to the previously defined Number Scale. That means if spacing standards change, the component updates system-wide with a single variable tweak.

Extending the System: Padding & Layout

For each button type (e.g. Primary, Secondary, etc.), I created colour tokens scoped by layer:

  • Surface/Default, Subtle, Lighter, Darker

  • Border/Default, Subtle, etc.

  • Text/Label


These tokens point back to foundational colours like Colours/Purple/500, enabling:

🔁 Theme swapping without redesign

⚖️ Predictable contrast and accessibility

🧼 Cleaner dev handoff (semantics > hex codes)

Button Variants: Interaction Without the Bloat

Using Figma’s component properties and variant logic, I covered all core use cases without creating visual clutter:

👆 States: Default, Hover, Pressed, Disabled

📏 Sizes: Small, Medium, Large

🖼 Icon presence: Start, End, Both, None

🔤 Text-only or filled buttons


By binding structure and style to tokens, each variant became an output of logic, not an isolated design artefact.

System Thinking Behind the Build

This wasn’t just about building “a button that looks good”—it was about creating a button that behaves well, plays nicely with others, and scales effortlessly.


Key principles applied:

  • Modularity over redundancy – Small changes don’t require full rework

  • Variables over overrides – Design decisions are made once, reused everywhere

  • Structure mirrors code – Devs can translate tokens to implementation with minimal ambiguity

  • Theming built-in – One button setup can support multiple brands or UI modes

Outcome

This button system became a template for interaction patterns across the product. Designers could move faster, devs had a clean map to implementation, and QA had a logical system to validate against.

It’s the kind of foundational UX infrastructure that doesn’t just look good—it makes everything else better too.

Inputs: Modular, Configurable, and Built with Tokens

Designing input fields that adapt to complexity without adding chaos

Input fields are deceptively simple. But in real-world products, they need to handle a variety of states (focus, error, disabled), sizes, icons, hints, labels, and accessibility concerns—often all at once.


Instead of designing one-off inputs, I approached them as flexible, token-powered components, made to scale across forms, modals, mobile screens, and edge cases.

Structured by Component Tokens

Each input is structured using its own component token set, tied directly to the global number scale. This gave me instant control over layout spacing, padding, radius, and icon sizing.

  • Radius → Radius/M

  • H-Padding → Horizontal space: Number Scale/2’s/L

  • V-Padding → Vertical space: Number Scale/2’s/XS

  • Spacing → Gap between label, text, and icons

  • Icon Size → Number Scale/2’s/2XL

These tokens ensured inputs visually aligned with buttons and other components, while still being flexible enough for size or theme tweaks. A design change in padding or icon size? Just update the token—no need to touch every variant.

Built for Flexibility, Powered by Properties

Using component properties, I enabled full control over what the input field shows without duplicating variants. Toggle-based controls let designers and developers:

  • Turn icons on/off (start or end)

  • Show or hide hint text

  • Update states (default, selected, error, success)

  • Inject label or input text inline


This meant we could support various use cases (e.g. search bars, date pickers, validation fields) within one single logic-driven component.

Token + Property Synergy = Scalable Forms

To manage state styling (e.g. error or success), I reused semantic colour tokens from the global system. For example:

  • Border/Error → Colours/Red/500

  • Border/Success → Colours/Green/500

  • Hint/Error → Colours/Red/700


This allowed:

🎨 Themeable validation feedback

✅ Accessible contrast by design

🔁 Reuse across any form without custom overrides

UX Thinking Behind the Build

My goal wasn’t just to design an input that looked polished—it was to build one that:

  • Works across edge cases without blowing up into 20 variants

  • Keeps dev handoff clean and modular

  • Follows WCAG alignment on spacing, contrast, and field labelling

  • Matches other components in feel and rhythm


This input structure became the template for forms across the system—unifying how we handle user data entry across web and mobile.

Outcome

With one master input component, we could build everything from simple forms to complex modals—without inconsistencies or maintenance debt. The tokens and properties made it future-proof, dev-friendly, and easy to extend.

It’s the kind of systemised interaction design that doesn’t just support product growth—it anticipates it.

Outcome & Reflections

By anchoring the dashboard in a scalable, token-driven system, we did more than just make it visually clean—we made it resilient to complexity. As new survey types, metrics, and customer segments were introduced, the design held its integrity. UI consistency remained intact. Developer velocity increased. And most importantly, the core goal was achieved: teams could now generate meaningful insights from survey data in under 5 minutes, with less cognitive friction and clearer decision paths.


This project reinforced something I deeply believe: great design isn’t just about what users see—it’s about what teams can build on.


Design systems aren’t just aesthetic frameworks; they’re decision frameworks. And when built with intent, they turn a reactive design process into a strategic asset.

Colour system (using variables and tokens)

From base colours to semantic meaning across surfaces, borders, and text

After defining our base colour palette and grayscale system, the next step was to create semantic colour tokens—a bridge between raw values and component-level usage. These tokens enable designers and engineers to apply colours like surface/default or text/caption without needing to remember hex codes or visual intent.

Why this matters:
A semantic system unlocks scalability. It removes the guesswork and supports theming, dark mode, and cross-product consistency—while still being flexible enough to evolve.

Strategic Palette Design

Each colour was developed from a 500-level base, then extended with shade values up to 950 and down to 50. The grayscale includes subtle hue shifts to avoid visual flatness—critical in modern UIs.


All tokens are named using a predictable structure (Colour/Blue/700), and all base colours were prepped in variables—even if not in active use—so future themes or feature modules can tap into them without friction.

Semantic Tokens: Bridging Visuals to Meaning

Here, I shifted from base colours to meaningful, abstracted tokens. Instead of assigning hex codes directly to components, I defined roles like:

Surface/Default

Border/Disabled

Text/Negative


These reference the core palette behind the scenes (e.g. Greyscale/700, Red/600, etc.). This abstraction allows:

Global theming with minimal change effort

Clearer handoff for devs and design QA

Future-proofing: swapping Text/Body from dark grey to white becomes trivial in dark mode

Token Mapping in Action

Each colour family (e.g. Purple, Red) follows the same semantic mapping structure—ensuring consistency across interaction states and brand extensions. I applied the same logic across all UI layers:

Surface tokens for background containers

Border tokens for outlines and dividers

Text/Icon tokens for legibility, emphasis, and accessibility


This allowed for easy reuse, predictable interaction design, and contrast tuning at a semantic level.

UX Thinking Behind the System

A colour system isn't just a palette—it’s a contract between design and code, and a tool for UI clarity.


Here’s what made this system truly effective:

Predictable contrast ratios (especially across surface + text pairings)

Accessible defaults built into the semantic structure

Effortless design QA—tokens speak for themselves (Text/Caption or Border/Darker)

Theming readiness baked in from the beginning

Number Scale & Radius Tokens

Creating a universal sizing system that scales across layout, components, and interaction design

To support consistent and reusable component design, I established a number-based scale using Figma variables. The idea was simple: define a core set of primitive values and give them human-readable size labels (e.g. XS, M, 2XL) to reduce guesswork and support component logic later on.

Rather than choosing arbitrary pixel values, I mapped everything to this unified scale—from spacing and padding to width, height, and border radius. This means fewer inconsistencies, easier updates, and a system that scales with product complexity.

Number Scale

The number scale starts at 2 and extends up to 999:

Lower values (2–24) cover small-scale spacing and detail-level UI

Mid-range (32–40) works for containers, cards, and modular layouts

999 ("Full") is reserved for stretch and full-width scenarios

Each step in the scale corresponds to tokens like 2XS, XS, M, 3XL, etc., allowing us to design with intent rather than pixels.

Applying Tokens to Radius

I then used the scale to create semantic corner radius tokens. Instead of defining custom corner values for every component, I assigned radius values like Radius/S, Radius/M, and Radius/Full.

This made it easier to:

Keep consistent rounding across buttons, inputs, and cards

Adjust radii system-wide from a single source of truth

Handle special cases (e.g. pills, circular avatars) with Radius/Full

Radius

XS

S

M

L

XL

Full

Extending the System: Padding & Layout

Padding, spacing, and layout constraints were also aligned to the same number tokens. This let me build clean, responsive components without constantly checking pixel values.

I scoped each token to its relevant use case in Figma (e.g. Gap, Corner radius, Text content, etc.), so designers only see relevant values based on context. That alone saved a ton of confusion and UI clutter.

This scoped approach allowed my team to work faster and more confidently—less scrolling through irrelevant tokens, more focus on structure and behaviour.

Key Insight: Design Systems Need Design Logic

When you're building a component library at scale, consistency isn’t just about the visuals—it’s about systemic thinking. This number scale system gave us:

A language to talk about spacing (“use M for default padding”)

A flexible structure that works across products and themes

A logic-driven foundation that scales from 1px tweaks to complex design handoff

Buttons: Tokenised, Responsive, and Built to Scale

Designing interactive components that are consistent, flexible, and easy to maintain

After building out the base colour system, number scale, and semantic tokens, I moved on to one of the most reused and critical components in any UI system: buttons.


Rather than treating buttons as isolated UI blocks, I approached them as token-driven templates—composed of interchangeable variables for size, padding, colours, and interaction states. This gave our team both visual consistency and practical agility.

Why Buttons Need to Be System-Smart

Buttons carry heavy responsibility. They guide action, convey hierarchy, and often set the tone for the rest of the product's UI. That’s why I engineered them around:

✳️ Component tokens – for structure (padding, icon size, radius)

🎨 Semantic colour tokens – for surface, border, and label text

🧩 Variants + properties – to cover states, sizes, and icons without redundancy


This setup ensures that every interaction is predictable, accessible, and easy to adapt—across screens, themes, or even different brands.

Component Tokens: Anatomy of a Button

Each button size (Small, Medium, Large) is defined through its own set of component tokens, including:

Radius – from Radius/S

Spacing – controlling gaps between text & icon

H-padding / V-padding – tokenised horizontal/vertical space

Full padding – used when applying padding uniformly

Icon Size – tied to the number scale


Rather than hardcoding these values in every variant, I linked each token to the previously defined Number Scale. That means if spacing standards change, the component updates system-wide with a single variable tweak.

Extending the System: Padding & Layout

For each button type (e.g. Primary, Secondary, etc.), I created colour tokens scoped by layer:

Surface/Default, Subtle, Lighter, Darker

Border/Default, Subtle, etc.

Text/Label


These tokens point back to foundational colours like Colours/Purple/500, enabling:

🔁 Theme swapping without redesign

⚖️ Predictable contrast and accessibility

🧼 Cleaner dev handoff (semantics > hex codes)

Button Variants: Interaction Without the Bloat

Using Figma’s component properties and variant logic, I covered all core use cases without creating visual clutter:

👆 States: Default, Hover, Pressed, Disabled

📏 Sizes: Small, Medium, Large

🖼 Icon presence: Start, End, Both, None

🔤 Text-only or filled buttons


By binding structure and style to tokens, each variant became an output of logic, not an isolated design artefact.

System Thinking Behind the Build

This wasn’t just about building “a button that looks good”—it was about creating a button that behaves well, plays nicely with others, and scales effortlessly.


Key principles applied:

Modularity over redundancy – Small changes don’t require full rework

Variables over overrides – Design decisions are made once, reused everywhere

Structure mirrors code – Devs can translate tokens to implementation with minimal ambiguity

Theming built-in – One button setup can support multiple brands or UI modes

Outcome

This button system became a template for interaction patterns across the product. Designers could move faster, devs had a clean map to implementation, and QA had a logical system to validate against.

It’s the kind of foundational UX infrastructure that doesn’t just look good—it makes everything else better too.

Inputs: Modular, Configurable, and Built with Tokens

Designing input fields that adapt to complexity without adding chaos

Input fields are deceptively simple. But in real-world products, they need to handle a variety of states (focus, error, disabled), sizes, icons, hints, labels, and accessibility concerns—often all at once.


Instead of designing one-off inputs, I approached them as flexible, token-powered components, made to scale across forms, modals, mobile screens, and edge cases.

Structured by Component Tokens

Each input is structured using its own component token set, tied directly to the global number scale. This gave me instant control over layout spacing, padding, radius, and icon sizing.

Radius → Radius/M

H-Padding → Horizontal space: Number Scale/2’s/L

V-Padding → Vertical space: Number Scale/2’s/XS

Spacing → Gap between label, text, and icons

Icon Size → Number Scale/2’s/2XL

These tokens ensured inputs visually aligned with buttons and other components, while still being flexible enough for size or theme tweaks. A design change in padding or icon size? Just update the token—no need to touch every variant.

Built for Flexibility, Powered by Properties

Using component properties, I enabled full control over what the input field shows without duplicating variants. Toggle-based controls let designers and developers:

Turn icons on/off (start or end)

Show or hide hint text

Update states (default, selected, error, success)

Inject label or input text inline


This meant we could support various use cases (e.g. search bars, date pickers, validation fields) within one single logic-driven component.

Token + Property Synergy = Scalable Forms

To manage state styling (e.g. error or success), I reused semantic colour tokens from the global system. For example:

Border/Error → Colours/Red/500

Border/Success → Colours/Green/500

Hint/Error → Colours/Red/700


This allowed:

🎨 Themeable validation feedback

✅ Accessible contrast by design

🔁 Reuse across any form without custom overrides

UX Thinking Behind the Build

My goal wasn’t just to design an input that looked polished—it was to build one that:

Works across edge cases without blowing up into 20 variants

Keeps dev handoff clean and modular

Follows WCAG alignment on spacing, contrast, and field labelling

Matches other components in feel and rhythm


This input structure became the template for forms across the system—unifying how we handle user data entry across web and mobile.

Outcome

With one master input component, we could build everything from simple forms to complex modals—without inconsistencies or maintenance debt. The tokens and properties made it future-proof, dev-friendly, and easy to extend.

It’s the kind of systemised interaction design that doesn’t just support product growth—it anticipates it.

Colour system (using variables and tokens)

From base colours to semantic meaning across surfaces, borders, and text

After defining our base colour palette and grayscale system, the next step was to create semantic colour tokens—a bridge between raw values and component-level usage. These tokens enable designers and engineers to apply colours like surface/default or text/caption without needing to remember hex codes or visual intent.

Why this matters:
A semantic system unlocks scalability. It removes the guesswork and supports theming, dark mode, and cross-product consistency—while still being flexible enough to evolve.

Strategic Palette Design

Each colour was developed from a 500-level base, then extended with shade values up to 950 and down to 50. The grayscale includes subtle hue shifts to avoid visual flatness—critical in modern UIs.


All tokens are named using a predictable structure (Colour/Blue/700), and all base colours were prepped in variables—even if not in active use—so future themes or feature modules can tap into them without friction.

Semantic Tokens: Bridging Visuals to Meaning

Here, I shifted from base colours to meaningful, abstracted tokens. Instead of assigning hex codes directly to components, I defined roles like:

Surface/Default

Border/Disabled

Text/Negative


These reference the core palette behind the scenes (e.g. Greyscale/700, Red/600, etc.). This abstraction allows:

Global theming with minimal change effort

Clearer handoff for devs and design QA

Future-proofing: swapping Text/Body from dark grey to white becomes trivial in dark mode

Token Mapping in Action

Each colour family (e.g. Purple, Red) follows the same semantic mapping structure—ensuring consistency across interaction states and brand extensions. I applied the same logic across all UI layers:

Surface tokens for background containers

Border tokens for outlines and dividers

Text/Icon tokens for legibility, emphasis, and accessibility


This allowed for easy reuse, predictable interaction design, and contrast tuning at a semantic level.

UX Thinking Behind the System

A colour system isn't just a palette—it’s a contract between design and code, and a tool for UI clarity.


Here’s what made this system truly effective:

Predictable contrast ratios (especially across surface + text pairings)

Accessible defaults built into the semantic structure

Effortless design QA—tokens speak for themselves (Text/Caption or Border/Darker)

Theming readiness baked in from the beginning

Number Scale & Radius Tokens

Creating a universal sizing system that scales across layout, components, and interaction design

To support consistent and reusable component design, I established a number-based scale using Figma variables. The idea was simple: define a core set of primitive values and give them human-readable size labels (e.g. XS, M, 2XL) to reduce guesswork and support component logic later on.

Rather than choosing arbitrary pixel values, I mapped everything to this unified scale—from spacing and padding to width, height, and border radius. This means fewer inconsistencies, easier updates, and a system that scales with product complexity.

Number Scale

The number scale starts at 2 and extends up to 999:

Lower values (2–24) cover small-scale spacing and detail-level UI

Mid-range (32–40) works for containers, cards, and modular layouts

999 ("Full") is reserved for stretch and full-width scenarios

Each step in the scale corresponds to tokens like 2XS, XS, M, 3XL, etc., allowing us to design with intent rather than pixels.

Applying Tokens to Radius

I then used the scale to create semantic corner radius tokens. Instead of defining custom corner values for every component, I assigned radius values like Radius/S, Radius/M, and Radius/Full.

This made it easier to:

Keep consistent rounding across buttons, inputs, and cards

Adjust radii system-wide from a single source of truth

Handle special cases (e.g. pills, circular avatars) with Radius/Full

Radius

XS

S

M

L

XL

Full

Extending the System: Padding & Layout

Padding, spacing, and layout constraints were also aligned to the same number tokens. This let me build clean, responsive components without constantly checking pixel values.

I scoped each token to its relevant use case in Figma (e.g. Gap, Corner radius, Text content, etc.), so designers only see relevant values based on context. That alone saved a ton of confusion and UI clutter.

This scoped approach allowed my team to work faster and more confidently—less scrolling through irrelevant tokens, more focus on structure and behaviour.

Key Insight: Design Systems Need Design Logic

When you're building a component library at scale, consistency isn’t just about the visuals—it’s about systemic thinking. This number scale system gave us:

A language to talk about spacing (“use M for default padding”)

A flexible structure that works across products and themes

A logic-driven foundation that scales from 1px tweaks to complex design handoff

Buttons: Tokenised, Responsive, and Built to Scale

Designing interactive components that are consistent, flexible, and easy to maintain

After building out the base colour system, number scale, and semantic tokens, I moved on to one of the most reused and critical components in any UI system: buttons.


Rather than treating buttons as isolated UI blocks, I approached them as token-driven templates—composed of interchangeable variables for size, padding, colours, and interaction states. This gave our team both visual consistency and practical agility.

Why Buttons Need to Be System-Smart

Buttons carry heavy responsibility. They guide action, convey hierarchy, and often set the tone for the rest of the product's UI. That’s why I engineered them around:

✳️ Component tokens – for structure (padding, icon size, radius)

🎨 Semantic colour tokens – for surface, border, and label text

🧩 Variants + properties – to cover states, sizes, and icons without redundancy


This setup ensures that every interaction is predictable, accessible, and easy to adapt—across screens, themes, or even different brands.

Component Tokens: Anatomy of a Button

Each button size (Small, Medium, Large) is defined through its own set of component tokens, including:

Radius – from Radius/S

Spacing – controlling gaps between text & icon

H-padding / V-padding – tokenised horizontal/vertical space

Full padding – used when applying padding uniformly

Icon Size – tied to the number scale


Rather than hardcoding these values in every variant, I linked each token to the previously defined Number Scale. That means if spacing standards change, the component updates system-wide with a single variable tweak.

Extending the System: Padding & Layout

For each button type (e.g. Primary, Secondary, etc.), I created colour tokens scoped by layer:

Surface/Default, Subtle, Lighter, Darker

Border/Default, Subtle, etc.

Text/Label


These tokens point back to foundational colours like Colours/Purple/500, enabling:

🔁 Theme swapping without redesign

⚖️ Predictable contrast and accessibility

🧼 Cleaner dev handoff (semantics > hex codes)

Button Variants: Interaction Without the Bloat

Using Figma’s component properties and variant logic, I covered all core use cases without creating visual clutter:

👆 States: Default, Hover, Pressed, Disabled

📏 Sizes: Small, Medium, Large

🖼 Icon presence: Start, End, Both, None

🔤 Text-only or filled buttons


By binding structure and style to tokens, each variant became an output of logic, not an isolated design artefact.

System Thinking Behind the Build

This wasn’t just about building “a button that looks good”—it was about creating a button that behaves well, plays nicely with others, and scales effortlessly.


Key principles applied:

Modularity over redundancy – Small changes don’t require full rework

Variables over overrides – Design decisions are made once, reused everywhere

Structure mirrors code – Devs can translate tokens to implementation with minimal ambiguity

Theming built-in – One button setup can support multiple brands or UI modes

Outcome

This button system became a template for interaction patterns across the product. Designers could move faster, devs had a clean map to implementation, and QA had a logical system to validate against.

It’s the kind of foundational UX infrastructure that doesn’t just look good—it makes everything else better too.

Inputs: Modular, Configurable, and Built with Tokens

Designing input fields that adapt to complexity without adding chaos

Input fields are deceptively simple. But in real-world products, they need to handle a variety of states (focus, error, disabled), sizes, icons, hints, labels, and accessibility concerns—often all at once.


Instead of designing one-off inputs, I approached them as flexible, token-powered components, made to scale across forms, modals, mobile screens, and edge cases.

Structured by Component Tokens

Each input is structured using its own component token set, tied directly to the global number scale. This gave me instant control over layout spacing, padding, radius, and icon sizing.

Radius → Radius/M

H-Padding → Horizontal space: Number Scale/2’s/L

V-Padding → Vertical space: Number Scale/2’s/XS

Spacing → Gap between label, text, and icons

Icon Size → Number Scale/2’s/2XL

These tokens ensured inputs visually aligned with buttons and other components, while still being flexible enough for size or theme tweaks. A design change in padding or icon size? Just update the token—no need to touch every variant.

Built for Flexibility, Powered by Properties

Using component properties, I enabled full control over what the input field shows without duplicating variants. Toggle-based controls let designers and developers:

Turn icons on/off (start or end)

Show or hide hint text

Update states (default, selected, error, success)

Inject label or input text inline


This meant we could support various use cases (e.g. search bars, date pickers, validation fields) within one single logic-driven component.

Token + Property Synergy = Scalable Forms

To manage state styling (e.g. error or success), I reused semantic colour tokens from the global system. For example:

Border/Error → Colours/Red/500

Border/Success → Colours/Green/500

Hint/Error → Colours/Red/700


This allowed:

🎨 Themeable validation feedback

✅ Accessible contrast by design

🔁 Reuse across any form without custom overrides

UX Thinking Behind the Build

My goal wasn’t just to design an input that looked polished—it was to build one that:

Works across edge cases without blowing up into 20 variants

Keeps dev handoff clean and modular

Follows WCAG alignment on spacing, contrast, and field labelling

Matches other components in feel and rhythm


This input structure became the template for forms across the system—unifying how we handle user data entry across web and mobile.

Outcome

With one master input component, we could build everything from simple forms to complex modals—without inconsistencies or maintenance debt. The tokens and properties made it future-proof, dev-friendly, and easy to extend.

It’s the kind of systemised interaction design that doesn’t just support product growth—it anticipates it.

charlesjaja.dny@gmail.com

charlesjaja.dny@gmail.com

2025 Charles Jaja

2025 Charles Jaja

Say hello