How Long Does It Take to Build a Design System Button? Before/After Comparison

Published: (December 21, 2025 at 09:20 PM EST)
4 min read
Source: Dev.to

Source: Dev.to

hanui-io

“Where’s the design system documentation?”
If you’ve worked on government or enterprise projects, you’ve heard this. Then you open a 200‑page PDF, hunt for color codes, copy spacing values, debate whether the border‑radius is 4 px or 8 px… half a day gone for one button.
Today I’m showing you actual code — before and after using a component library.

Case 1: Building a Button

Before: Implementing from Design System PDF

// Step 1: Find color values in design guide (10 min)
// Primary: #0A5ECA, Hover: #0852B2, Active: #064794...

// Step 2: Write CSS (30 min)
.btn-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-width: 80px;
  height: 48px;
  padding: 0 20px;
  border-radius: 6px;
  font-size: 16px;
  font-weight: 500;
  background-color: #0A5ECA;
  color: #FFFFFF;
  border: none;
  cursor: pointer;
  transition: background-color 0.2s;
}
.btn-primary:hover   { background-color: #0852B2; }
.btn-primary:active  { background-color: #064794; }
.btn-primary:disabled{
  opacity: 0.5;
  cursor: not-allowed;
}
.btn-primary:focus-visible{
  outline: 2px solid #0A5ECA;
  outline-offset: 2px;
}

// Step 3: Write component (20 min)
function Button({ children, ...props }) {
  return (
    <button {...props}>{children}</button>
  );
}

// Step 4: Add variants? (1 hour)
// secondary, tertiary, danger… find each color, add CSS

// Step 5: Add sizes? (30 min)
// xs, sm, md, lg, xl… calculate height, padding, font‑size

// Total time: 2‑3 hours
// And next project? Start over.

After: Using HANUI

npx hanui add button
import { Button } from '@/components/ui/button';

// Done. Use immediately.
<Button>Default Button</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="danger">Delete</Button>
<Button isLoading>Saving…</Button>
<Button icon={<SearchIcon />}>Search</Button>

Time: 10 seconds

8 variants, 6 sizes, loading state, icon support — all included. Accessibility (aria-busy, aria-disabled, focus ring) is applied automatically.

Case 2: Form Field

Before: Manual Implementation

function FormField({ label, error, helperText, required, children }) {
  const id = useId();
  const errorId = `${id}-error`;
  const helperId = `${id}-helper`;

  return (
    <div>
      <label htmlFor={id}>
        {label}
        {required && <span>*</span>}
      </label>

      {/* How do I pass id, aria-describedby to children? */}
      {/* cloneElement? Context? */}
      {children}

      {error && (
        <p id={errorId}>{error}</p>
      )}

      {helperText && (
        <p id={helperId}>{helperText}</p>
      )}
    </div>
  );
}

// aria-describedby connection?
// Input error styling?
// Error icon?
// Screen reader support?
// … complexity grows

After: Using HANUI

npx hanui add form-field input
import {
  FormField,
  FormLabel,
  FormError,
  FormHelperText,
} from '@/components/ui/form-field';
import { Input } from '@/components/ui/input';

<FormField>
  <FormLabel>Email</FormLabel>
  <Input type="email" />
  <FormError>Invalid email format</FormError>
</FormField>

<FormField>
  <FormLabel>Username</FormLabel>
  <Input type="text" />
  <FormHelperText>Username is available</FormHelperText>
</FormField>

Context automatically connects id and ARIA attributes. Error/success icons auto‑display. role="alert" and aria-live="polite" are applied.

Case 3: Header + Mega Menu

Building this from scratch takes days.

Before: Consider All These

  • Responsive (mobile hamburger menu)
  • Mega‑menu dropdown
  • Keyboard navigation (Tab, Arrow, Escape)
  • Focus trap
  • Scroll behavior (sticky/hide)
  • WAI‑ARIA patterns

Honestly, building this properly takes a week.

After: Using HANUI

npx hanui add header
import { HeaderWithMegaMenu } from '@/components/ui/header';

// Use <HeaderWithMegaMenu /> directly – mega menu, mobile support,
// keyboard navigation, scroll behavior are all included.

Real Comparison

TaskManualWith Library
Button (with variants)2‑3 hours10 seconds
Form Field (accessible)3‑4 hours10 seconds
Header + Mega Menu3‑5 days10 seconds
Select (search, multi)1‑2 days10 seconds
Modal (focus trap)Half day10 seconds

Things Often Missed When Building Manually

  • aria-describedby connection
  • aria-expanded, aria-haspopup
  • Focus management
  • Escape key to close
  • Screen‑reader announcements

The Hidden Cost

The real problem with manual implementation isn’t just time.

1. Inconsistency

/* Developer A */
.btn { border-radius: 4px; }

/* Developer B */
.button { border-radius: 6px; }

/* Developer C */
.cus { border-radius: 5px; }

When each team member copies‑pastes values from a PDF, subtle differences creep in, leading to a fragmented UI and extra maintenance overhead.

Using a component library like HANUI eliminates the guesswork, guarantees accessibility, and lets you ship features in seconds instead of days.

tom-btn {
  border-radius: 8px;
}

2. Missing Accessibility

When you’re busy, ARIA attributes get skipped. “I’ll add them later” becomes “failed the audit.”

3. Maintenance Hell

Design system updates? Manually update all components across all projects.

Summary

ApproachTime required
Building design‑system components from scratchHours to days
Using a well‑built component librarySeconds

If you’re working on Korean government projects, HANUI provides KRDS‑compliant React components out of the box.

npx hanui init
npx hanui add button input select form-field header modal

5 minutes to set up. Spend the rest of your time on business logic.

GitHub:
Documentation

Back to Blog

Related posts

Read more »

Design System with CSS

Quick Summary If you have set out on using a design system for your website without the help of any popular framework or library—just pure CSS—you've come to t...

Design System: Governance and Adoption

Introduction Building a design system is only half of the work. Yes, it's challenging to evaluate multiple options, gather feedback from stakeholders, and impl...