What Makes a Good Design System in Frontend Engineering
A good design system is a product that has a roadmap, ownership, documentation, versioning, and feedback loops.
What is a design system?
A design system is a set of standardised building blocks and guidelines that enable teams to create consistent, scalable, and accessible user interfaces across projects.
They shape how teams collaborate, how products evolve, and how fast organisations can move without breaking consistency or accessibility.
Components of a Design System
Design Principle:
Every organisation has unique needs and goals. Communicating these through a set of principles helps shape how they present their product. It aids in making crucial design decisions.
An example of a Design principle is "Clarity and Simplicity".
This means straightforward flows with clear instructions and minimal steps would be prioritised.
Guided by Clarity & Simplicity, my signup form would have:
- One primary action per screen
- Clear field labels (not placeholders as labels)
- Inline validation with plain language
Instead of:
"Invalid input"
The design system enforces:
"Password must be at least 8 characters"
Design Tokens
Design tokens are named entities that store design-related values. These values can include colours, typography scales, spacing units, and shadows. When implemented correctly, they create a single source of truth, making theming and branding possible without rewrites.
There are 3 tiers of token;
Base tokens: Raw, hard-coded values that are the most atomic units in a design system. These are the actual values that never reference other tokens.
// tokens/base.json
{
"color": {
"base": {
"blue": {
"600": { "value": "#2563eb" },
"700": { "value": "#1d4ed8" }
},
"slate": {
"50": { "value": "#f8fafc" },
"300": { "value": "#cbd5e1" },
"900": { "value": "#0f172a" }
},
"white": { "value": "#ffffff" },
"transparent": { "value": "transparent" }
}
}
}
Semantic Token: Purpose-based tokens that reference base tokens. They describe the intent or purpose rather than the appearance. With semantic tokens, when your organisation rebrands, you change the token values, not every affected component.
{
"color": {
"brand": {
"primary": { "value": "{color.base.blue.600}" },
"primaryHover": { "value": "{color.base.blue.700}" },
"primaryActive": { "value": "{color.base.blue.800}" },
"secondary": { "value": "{color.base.slate.500}" },
"secondaryHover": { "value": "{color.base.slate.600}" }
},
"text": {
"primary": { "value": "{color.base.slate.900}" },
"secondary": { "value": "{color.base.slate.600}" },
"inverse": { "value": "{color.base.white}" },
"disabled": { "value": "{color.base.slate.400}" }
},
"background": {
"base": { "value": "{color.base.white}" },
"surface": { "value": "{color.base.slate.50}" },
"sunken": { "value": "{color.base.slate.100}" },
"transparent": { "value": "{color.base.transparent}" }
},
"border": {
"default": { "value": "{color.base.slate.300}" },
"focus": { "value": "{color.base.blue.600}" },
"error": { "value": "{color.base.red.500}" },
"transparent": { "value": "{color.base.transparent}" }
},
"feedback": {
"success": { "value": "{color.base.green.500}" },
"error": { "value": "{color.base.red.500}" },
"warning": { "value": "{color.base.yellow.500}" },
"info": { "value": "{color.base.blue.500}" }
}
},
"spacing": {
"xs": { "value": "{spacing.base.2}" },
"sm": { "value": "{spacing.base.3}" },
"md": { "value": "{spacing.base.4}" },
"lg": { "value": "{spacing.base.6}" },
"xl": { "value": "{spacing.base.8}" }
},
}
When to use semantic tokens:
- All UI components (buttons, inputs, cards, modals)
- Product interfaces
- Anywhere that needs automatic theme support
- When consistency and meaning matter more than specific values
Component tokens: define how a particular component looks. They reference semantic tokens and contain all styling decisions for a component.
Component tokens are optional for smaller systems where semantic tokens provide sufficient abstraction.
{
"button": {
"primary": {
"backgroundColor": { "value": "{color.brand.primary}" },
"backgroundColorHover": { "value": "{color.brand.primaryHover}" },
"backgroundColorActive": { "value": "{color.brand.primaryActive}" },
"textColor": { "value": "{color.text.inverse}" },
"borderColor": { "value": "{color.border.transparent}" },
"paddingBlock": { "value": "{spacing.sm}" },
"paddingInline": { "value": "{spacing.md}" },
"fontSize": { "value": "{fontSize.md}" },
"fontWeight": { "value": "{fontWeight.medium}" },
"borderRadius": { "value": "{borderRadius.md}" }
},
"secondary": {
"backgroundColor": { "value": "{color.background.transparent}" },
"backgroundColorHover": { "value": "{color.background.sunken}" },
"textColor": { "value": "{color.text.primary}" },
"borderColor": { "value": "{color.border.default}" },
"paddingBlock": { "value": "{spacing.sm}" },
"paddingInline": { "value": "{spacing.md}" },
"fontSize": { "value": "{fontSize.md}" },
"borderRadius": { "value": "{borderRadius.md}" }
}
},
"input": {
"default": {
"backgroundColor": { "value": "{color.background.base}" },
"textColor": { "value": "{color.text.primary}" },
"borderColor": { "value": "{color.border.default}" },
"borderColorFocus": { "value": "{color.border.focus}" },
"borderColorError": { "value": "{color.border.error}" },
"paddingBlock": { "value": "{spacing.sm}" },
"paddingInline": { "value": "{spacing.md}" },
"fontSize": { "value": "{fontSize.md}" },
"borderRadius": { "value": "{borderRadius.md}" }
}
},
"card": {
"default": {
"backgroundColor": { "value": "{color.background.base}" },
"borderColor": { "value": "{color.border.default}" },
"borderRadius": { "value": "{borderRadius.lg}" },
"padding": { "value": "{spacing.lg}" }
}
}
}
Use component tokens for:
- Large systems with many complex components
- Products requiring extensive customisation options
- Systems serving multiple brands or products
- Centralising component styling decisions
Foundations:
The foundations of a design system ensure consistency and quality in design and development. It's built on two main pillars: d*esign tokens and system architecture*.
Foundational elements include:
- Typography
- Color system
- Accessibility standards
- Spacing and Layout
- Iconography
What makes a solid foundation?
- Mathematical consistency - using modular scales for type and spacing
//Good - Spacing uses consistent ratio (e.g., 1.5x multiplier)
spacing: {
xs: "0.5rem", // 8px
sm: "0.75rem", // 12px
md: "1rem", // 16px
lg: "1.5rem", // 24px
xl: "2.25rem", // 36px
xxl: "3.375rem" // 54px
}
// Bad - No pattern, impossible to memorize
spacing: {
tiny: "0.3125rem", // 5px
small: "0.625rem", // 10px
medium: "0.9375rem", // 15px
large: "1.375rem", // 22px - random
huge: "2.125rem" // 34px
}
- Scalable naming conventions - clear, predictable names that grow with the system
// GOOD - Semantic tokens (references, flexible)
const semanticTokens = {
colors: {
action: {
primary: baseTokens.colors.blue[200],
primaryHover: baseTokens.colors.blue[300],
},
feedback: {
success: baseTokens.colors.green[500],
error: baseTokens.colors.blue[500],
},
text: {
primary: baseTokens.colors.slate[900],
secondary: baseTokens.colors.slate[600],
}
}
};
// Bad - what happens when "blue" becomes purple?
colors: {
blueButton: "#2563eb",
darkBlueHover: "#1d4ed8",
lightBlueBackground: "#dbeafe"
}
// Now you're stuck with:
blueButton: "#7c3aed" // This is purple
Component Library
A component library is a collection of UI components within a design system.
What makes a good component library?
- Single Responsibility: Each component should have a single responsibility.
// Good
// Bad - ONE component trying to be everything
- Composable: It doesn’t try to predict every use case with prebuilt “big” components like in the button example above. Instead, it gives small, flexible primitives that can be composed.
- Consistent and predictable API
//Good- Same pattern in all components. Learn once, apply everywhere
//Bad - Each component uses different naming. Difficult to learn
// uses 'color'
// uses 'variant'
// uses 'theme'
// uses 'type'
- Smart defaults with Controlled Flexibility:
// Works great with/without props, uses variant="primary", size="md" as default
// But allows customisation when needed
// Bad
- Proper Prop Types & TypeScript Support
// Inherits valid button props and ensures only valid customizations
interface ButtonProps extends Omit<
React.ComponentPropsWithoutRef<'button'>,
'style' // Block inline styles
> {
variant?: 'primary' | 'secondary';
size?: 'sm' | 'md' | 'lg';
}
// Bad - anything goes for props
const Button = ({
variant,
size,
disabled,
loading,
children,
onClick,
...props // anything works
}) => {
return (
);
};
- Accessible by Default
//Good - Keyboard works, screen readers announce "button", forms work
//
//bad - lacks focus, keyboard support, and screen reader compatibility
Click me
Pattern Library
A Pattern Library is a collection of design patterns that provide solutions to common design problems and user interface challenges. These patterns are reusable and follow best practices to ensure consistency and usability across an application or suite of applications.
Examples: Form Validation, Navigation.
What makes a strong pattern library?
- Solves Real Problems:
// Form validation pattern used across 20+ forms
- Proper documentation:
## Empty State Pattern
### When to use
- List/table with no data
- Search with no results
- New user with no content
### When NOT to use
- Loading states (use skeleton instead)
- Errors (use error pattern)
### Accessibility
- Must include descriptive text
- Action button should be clearly labeled
- Use role="status" for dynamic updates
Handles Edge Cases: The pattern addresses loading states, errors, empty states, and validation - not just the happy path.
Tooling and Infrastructure
Tools like Storybook or similar for component development, visual regression testing to catch unintended changes, automated accessibility testing, and a clear publishing and versioning strategy.
Good systems have CI/CD that runs tests on every PR, automatically publishes packages, and generates changelogs from commits.
Testing
A design system demands rigorous testing at multiple levels. Unit tests verify component logic and prop handling.
Visual regression testing catches unintended UI changes. Accessibility testing ensures WCAG compliance.
Integration tests confirm components work together correctly.
Documentation
Documentation is critical for the success of a design system. It ensures that all stakeholders including designers, developers, and other team members understand how to use and maintain the system.
Thorough documentation is provided for every component and pattern, including usage guidelines, code examples, and accessibility considerations. It's easy for designers and developers to understand and implement.
Real World Example: Atlassian Design System
Atlassian, a leading provider of collaboration software, developed the Atlassian Design System to unify the user experience across its suite of products including Jira, Confluence, Bitbucket, and Trello. It serves as a comprehensive framework that consolidates design patterns, guidelines, and reusable components to ensure consistency, efficiency, and usability across all Atlassian products.
Atlassian Design Principles
- Trusted fundamentals before comprehensive patterns
- Meet system needs before delivering individual features
- Bring people on the journey before helping for the moment
Atlassian's Foundation: Colour Palette

Source : Atlassian colour palette
Atlassian's Design Token: Text Color

Atlassian's Component Library: Button

Source : Atlassian button component
Atlassian's Pattern Library: Form Validation

Source : Atlassian form pattern
Atlassian's Documentation
Atlassian Design System is supported by a comprehensive documentation that serves as a central reference for designers, developers, and product teams. Documentation includes design principles, usage guidelines, code snippets, and design tokens. See here
Other Examples of design systems
- Material Design by Google
- Polaris by Shopify
- Fluent Design System by Microsoft
- Pajamas by Gitlab
- Carbon Design System by IBM
Conclusion
A good design system should:
- Be aligned with the brand identity
- Accelerate development velocity without sacrificing quality
- Ensure consistency across products while allowing necessary flexibility
- Reduce decision fatigue for common UI patterns
- Scale as the organisation grows
- Have proper documentation, be easy to use and maintain.
References
https://www.figma.com/blog/design-systems-101-what-is-a-design-system/
https://atlassian.design/
Building Design Systems: Unify User Experiences through a Shared Design Language Edition: 1st ed. By Sarrah Vesselov and Taurie Davis
https://storybook.js.org/tutorials/design-systems-for-developers/
https://medium.com/@marcintreder/design-system-sprint-4-design-principles-8efb22d8a208
https://atlassian.design/get-started/about-atlassian-design-system#our-principles