
새롭게 시작하는 거대한 프로젝트 속에는 또 다른 거대한 과제가 숨어 있었다. 바로 디자인 시스템 구축이었습니다.
이번 프로젝트는 단순히 두 개의 프로젝트를 하나로 합치는 것을 넘어, 디자인 요소 간 불일치로 인해 UX가 저하되고, 개발 및 유지보수 과정에서도 비효율성이 발생하는 문제를 해결하려고 하였습니다.
저희 서비스는 4개의 웹 페이지와 1개의 앱 프로젝트 등, 총 5개 이상의 프로젝트로 구성되어 있습니다. 하지만 각기 다른 디자이너가 작업했기 때문에 디자인 일관성이 부족한 상태였습니다. 이런 상황은 사용자 경험(UX) 측면에서도 아쉬움으로 작용할 수밖에 없었습니다.
이에 따라, “조직 개편으로 인한 공동 자산 필요성 및 제품의 플랫폼화”라는 목표를 설정하고, 이번 신규 프로젝트를 진행하면서 디자인 시스템을 함께 구축하기로 했습니다.
이 프로젝트는 단순한 통합을 넘어, 우리 서비스의 아이덴티티 확립 이었습니다.
이를 해결하기 위해 상위조직에게 찾아가 디자인 시스템 로드맵을 제안하며 프로젝트를 본격적으로 시작했습니다.
- Turborepo를 활용해 모노레포 구조로 서비스들을 통합 관리하여 재사용성과 확장성을 강화합니다.
- Mantine과 Panda CSS를 조합해 컴포넌트를 제작하고, 디자인 토큰 기반의 시스템을 구축합니다.
- 설계 과정에서 효율성과 유연성을 높이는 도구와 라이브러리를 선택했습니다.
일단 설계에 앞서 요구사항을 정리해보고 정리해보았습니다.
요구사항
| 항목 | Tailwind CSS | PandaCSS |
|---|---|---|
| 설정 및 디지안 시스템 구축 방식 | tailwind.config.js를 통해 높은 커스터마이징 가능. | 중앙화된 파일에서 디자인 토큰과 테마를 설정. |
| 학습 난이도 | 중간, 유틸리티 클래스를 익히는 데 시간이 필요함. | 특수한 몇 가지 유틸리티 클래스만 익히면 됨. |
| 스타일링 방식 | JSX/HTML에 클래스를 직접 추가하여 스타일링. | 스타일 토큰을 사용하며 JSX props와 통합 가능. |
| 프레임워크 통합 | React, Next.js 등 대부분의 프레임워크에서 잘 지원됨. | 현대적인 프레임워크와 강력한 TypeScript 지원에 초점. |
| TypeScript 지원 | 주로 설정 파일에서의 기본적인 지원. | 자동 완성과 타입 지원을 포함한 강력한 TypeScript 지원. |
| 커뮤니티 크기 | 크고 잘 확립된 커뮤니티. | 작지만 꾸준히 성장 중인 커뮤니티. |
스타일 방식에 대한 선택 이유
// Tailwind
<div class="bg-blue-100 border-t border-b border-blue-500 text-blue-700 px-4 py-3" role="alert">
<p class="font-bold">Informational message</p>
<p class="text-sm">Some additional text to explain said message.</p>
</div>
Tailwind CSS의 클래스 이름은 직관적이지만, 클래스 수가 많아질수록 가독성이 떨어질 수 있습니다.
// panda css
<div class={css({
bg: 'blue.100',
borderTop: '1px solid',
borderBottom: '1px solid',
borderColor: 'blue.500',
color: 'blue.700',
px: 4,
py: 3,
})}>
<p class={css({
textStyle: 'font-bold',
})}>Informational message</p>
<p class={css({
textStyle: 'text-sm',
})}>Some additional text to explain said message.</p>
</div>;
Panda CSS는 객체 기반으로 스타일을 정의하여 가독성과 재사용성을 높입니다.
(다음 글에서는 PandaCSS의 디자인 토큰 시스템과 컴포넌트 제작에서의 구체적인 활용 방안을 다룰 예정입니다.)
monorepo: turborepo
라이브러리 선택: ui -> mantine, css -> panda-css
- 디자인 토큰은 Value → Primitive → Semantic 레이어를 기반으로 스타일을 관리하며, 프로젝트 전반에 일관된 스타일과 확장성을 제공합니다.
- 디자인 토큰을 통해 변경 사항을 중앙에서 관리하며, 팀 간 협업과 유지보수가 용이합니다.
- Semantic 레이어를 활용해 의미 중심의 스타일 정의로 사용성과 가독성을 개선합니다.
디자인 토큰을 사용하면 프로젝트 전반에 걸쳐 일관된 스타일을 유지할 수 있으며, 변경 사항을 쉽게 관리할 수 있습니다. 주어진 구조에 따라 Value, Primitive, Semantic의 세 가지 레이어를 통해 디자인 토큰을 구현하는 방식에 대해 자세히 설명하겠습니다.
디자인 토큰 구조

// Value: 실제 값
const value = '#06F' as const; // Hex 코드, 픽셀 값 등
// Primitive: Value를 그룹화하여 추상화
const blue = {
400: value, // 기본 파란색 톤 (400번 값)
} as const;
// Semantic: 실제 사용 사례에 따라 이름 부여
const PrimaryNormal = blue[400]; // 주 색상
- Mantine의 베이스 컴포넌트에 디자인 토큰을 적용하여 재사용 가능하고 일관된 컴포넌트를 제작합니다.
- Panda CSS를 사용해 선언적이고 효율적인 스타일 정의가 가능합니다.
디자인 토큰은 스타일의 일관성과 확장성을 보장하지만, 실제로 시스템의 가치를 실현하려면 이를 기반으로 컴포넌트를 구축해야 합니다.
앞서 선택한 mantine의 베이스에 디자인 토큰을 입히는 걸 디자이너 분들에게 제안 하였고 이를 잘 받아 주셨습니다.
장점
1. 공식 홈페이지가 존재 하여 디자인 가이드 및 구현된 기능을 참고 하여 제작 가능
2. 이미 검증된 라이브러리를 사용 함으로써 개발자/디자이너 효용성 증가
이제 디자인 토큰을 활용해 재사용 가능한 컴포넌트를 제작하는 방법을 살펴보겠습니다.
root/
├── apps/ # 각 서비스 애플리케이션
│ ├── service-a/ # 서비스 A
│ │ ├── public/ # 정적 파일
│ │ ├── src/ # 서비스 A의 소스 코드
│ │ │ ├── components/ # 서비스 A 전용 컴포넌트
│ │ │ └── pages/ # Next.js 페이지 디렉토리
│ │ ├── package.json # 서비스 A의 의존성 관리
│ │ └── tsconfig.json # 서비스 A의 TypeScript 설정
│ ├── service-b/ # 서비스 B
│ └── service-c/ # 서비스 C
│
├── packages/ # 공통 패키지 모음
│ ├── design-system/ # 디자인 시스템
│ │ ├── src/ # 디자인 시스템 소스 코드
│ │ │ ├── components/ # 공통 컴포넌트
│ │ │ │ ├── Button/ # 예: 버튼 컴포넌트
│ │ │ │ └── Modal/ # 예: 모달 컴포넌트
│ │ │ ├── hooks/ # 디자인 시스템 전용 훅
│ │ │ ├── tokens/ # 디자인 토큰
│ │ │ │ ├── colors.ts # 색상 토큰
│ │ │ │ ├── typography.ts # 타이포그래피 토큰
│ │ │ │ └── spacing.ts # 여백 토큰
│ │ │ └── utils/ # 유틸리티 함수
│ │ ├── package.json # 디자인 시스템의 의존성 관리
│ │ └── tsconfig.json # 디자인 시스템의 TypeScript 설정
│
├── node_modules/ # 의존성 모음 (루트 레벨)
├── turbo.json # Turborepo 설정 파일
├── package.json # 루트 의존성 관리
├── tsconfig.base.json # 모노레포 전체 TypeScript 설정
└── README.md # 프로젝트 설명
이렇게 패키지로 분리하여 재활용성과 확장성이 높아집니다.
만타인과 panda css 를 사용해서 컴포넌트를 만드는 예제
import type { SelectProps as MSelectProps } from '@mantine/core';
import { Select as MSelect } from '@mantine/core';
import { css } from '@styles/css';
const classNames = {
root: css({
h: '100%',
}),
wrapper: css({
height: '100%',
}),
input: css({
borderColor: 'lineBaseNormal',
bg: 'bgBaseNormal',
color: 'labelNormal',
h: '100%',
}),
dropdown: css({
borderColor: 'lineBaseNormal',
bg: 'bgBaseNormal',
color: 'labelNormal',
}),
option: css({
_hover: {
bg: 'fillAlternative',
},
}),
} as const;
export type SelectProps = Omit<MSelectProps, 'classNames'>;
const Select = (props: SelectProps) => (
<MSelect {...props} classNames={classNames} />
);
export default Select;
Mantine의 classNames 속성은 컴포넌트의 특정 부분(예: input, dropdown)을 커스터마이징할 수 있는 강력한 기능을 제공합니다. 이 속성을 Panda CSS의 css 또는 cva(Class Variance Authority)와 결합하면, 스타일링을 디자인 토큰 기반으로 관리하면서도 선언적인 스타일 정의가 가능합니다.
서비스에서 디자인 시스템 컴포넌트를 사용하는 코드
import React from 'react';
import Select from '@workspace/design-system/Select';
const options = [
{ value: 'option1', label: 'Option 1' },
{ value: 'option2', label: 'Option 2' },
{ value: 'option3', label: 'Option 3' },
];
const Example = () => (
<div style={{ maxWidth: 300, margin: '0 auto' }}>
<Select
label="Choose an option"
placeholder="Select..."
data={options}
customStyles={{
input: css({ fontSize: 'lg', bg: 'gray.50' }),
}}
/>
</div>
);
export default Example;
디자인 토큰과 Mantine, Panda CSS를 활용한 컴포넌트 제작은 스타일의 일관성을 유지하면서도 확장성과 재사용성을 보장합니다. 이렇게 구축된 컴포넌트는 디자인 시스템의 가치를 실질적으로 실현하며, 개발자와 디자이너 간 협업을 강화합니다.
Storybook을 활용해 컴포넌트를 문서화하고, 팀 내에서 시각적으로 공유하여 협업 효율성을 높입니다.
디자인 시스템의 효과를 극대화하려면, 모든 팀원이 시스템의 구성 요소와 사용 방법을 쉽게 이해하고 접근할 수 있도록 문서화와 시각화가 중요합니다. 이를 통해 개발자와 디자이너 간의 협업을 원활히 하고, 시스템의 유지보수를 간소화할 수 있습니다.
Storybook을 활용한 문서화
Controls를 사용해 컴포넌트의 변형(variant)과 속성을 실시간으로 테스트할 수 있습니다.
스토리북 예시 이미지
Controls 패널을 사용하면 컴포넌트의 속성(props)을 실시간으로 변경하며 결과를 확인할 수 있습니다.
디자이너와 개발자 간의 협업을 강화하기 위해 피드백 루프를 구축하고, 실시간 협업 도구를 활용합니다.
협업 프로세스 예시 이미지
디자이너: 컴포넌트 생성
개발자: 작업 확인 및 준비
개발자: 배포 및 QA 요청
디자이너: QA 진행
개발자: QA 피드백 반영
작업 완료
이 협업 프로세스는 팀 간의 원활한 협업과 작업 효율성을 극대화하는 데 기여할 수 있습니다.
일관된 사용자 경험 제공
협업 효율성 증대
개발 및 유지보수 비용 절감
디자인 시스템은 단순히 UI 요소를 관리하는 도구를 넘어, 팀 전체의 작업 방식을 변화시키고, 조직의 역량을 강화하는 기반이 되었습니다.
우리 팀은 디자인 시스템을 통해 효율적인 협업 환경을 구축하고, 일관된 사용자 경험을 제공하며, 생산성과 유지보수성을 동시에 향상시킬 수 있었습니다.
앞으로도 이 시스템을 지속적으로 발전시키며, 새로운 요구사항과 기술 변화에 유연하게 대응할 것입니다.
디자인 시스템은 우리 조직이 더 빠르게 성장하고, 더 나은 제품을 제공할 수 있도록 하는 핵심 자산으로 남을 것입니다.