Introduction
빅태블릿 제품에서 사용하는 공통 컴포넌트와 디자인 토큰을 Storybook에서 확인합니다.
Company · Open Source · NPM · 2025-2026
컴포넌트 모음에서 제품을 조립·검증하는 인터페이스 플랫폼으로
토큰과 테마부터 레이아웃, 컴포넌트 API, 모션, 테스트, 릴리즈까지 제품 팀이 같은 기준으로 화면을 만들고 검증할 수 있는 기반을 구축했습니다.
사내 여러 제품이 같은 UI 기준을 사용하려면 Button, TextField, Modal 같은 개별 컴포넌트만으로는 부족했습니다. 색상과 테마, 화면 레이아웃, 모바일 내비게이션, 접근성, 모션까지 제품을 구성하는 공통 규칙이 필요했고, React뿐 아니라 서로 다른 프론트엔드 환경에서도 같은 인터페이스 기준을 사용할 수 있어야 했습니다.
컴포넌트가 늘어나면서 구현 방식의 차이도 누적되었습니다. 모션은 CSS keyframe과 shouldRender/isExiting/onAnimationEnd 패턴이 혼재해 exit animation 이후 unmount 처리가 컴포넌트마다 달랐고, anchor와 button을 모두 지원하는 navigation item은 각 element의 native attribute와 disabled semantics를 타입과 런타임에서 함께 보장해야 했습니다.
Storybook과 테스트 환경에서도 실제 제품과 차이가 발생했습니다. iframe의 기본 여백 때문에 fixed-position 컴포넌트가 실제 viewport와 다르게 렌더링되거나, animation callback의 실행 시점 때문에 unmount 테스트가 불안정했습니다. Dark mode에서는 일부 하드코딩된 색상이 토큰 체계에서 벗어나 대비가 깨지는 문제도 있었습니다.
패키지 배포 역시 제품 기반의 일부였습니다. 기존 NPM publish 과정의 token과 OIDC 의존성을 정리하고, 지속적으로 릴리즈할 수 있는 공급망을 구축할 필요가 있었습니다.
CSS custom properties를 기반으로 색상과 테마를 light/dark/system 구조로 정리하고, ThemeProvider와 useTheme을 통해 제품과 Storybook에서 동일한 테마 규칙을 사용하도록 했습니다. Storybook toolbar에서도 세 테마를 직접 전환하며 컴포넌트를 검증할 수 있게 구성했습니다.
개별 컴포넌트를 넘어 화면 자체를 같은 기준으로 조립할 수 있도록 Container, Section, Stack, Grid 등의 layout primitive를 추가했습니다. max-width, spacing, responsive grid, flex direction처럼 제품에서 반복되던 레이아웃 패턴을 컴포넌트 API로 끌어올렸습니다.
모바일 환경에서는 BottomNav, BottomNavItem, BottomNavSpacer를 추가하고, Sidebar에 mode=“auto”를 도입했습니다. 600px 미만에서는 CSS media query를 통해 sidebar가 bottom navigation으로 전환되도록 해 동일한 navigation 구조를 viewport에 따라 재사용할 수 있게 했습니다.
SidebarItem과 BottomNavItem은 as=“a” | “button”을 discriminated union으로 모델링했습니다. Anchor에서는 target, rel, download를, button에서는 type, form을 타입 수준에서 구분했습니다. Disabled 상태 역시 anchor에는 aria-disabled, tabIndex=-1, preventDefault를 적용하고 button에는 native disabled를 사용해 element semantics를 유지했습니다.
컴포넌트마다 달랐던 exit animation을 react-spring 기반 presence pattern으로 통합했습니다. useSpringPresence에 onExitComplete를 제공해 animation 이후 unmount를 공통 처리하고, Modal과 Alert는 overlay와 panel의 motion lifecycle을 분리했습니다. Toast 역시 timer와 별도의 exiting state 대신 spring lifecycle을 사용하도록 변경했습니다.
모든 interaction을 같은 animation 정책으로 강제하지는 않았습니다. Dropdown처럼 선택이나 ESC 입력 이후 즉각적인 종료가 중요한 컴포넌트는 enter-only pattern을 유지해 사용자 경험과 구현 일관성 사이의 trade-off를 조정했습니다.
Storybook iframe의 body margin/padding을 reset해 fixed UI를 실제 viewport와 동일한 조건에서 검증하고, 테스트 환경에서는 spring animation을 skip해 exit 이후 unmount 테스트가 결정적으로 실행되도록 구성했습니다.
React 제품에는 Rollup 기반 패키지를 제공하고, React를 사용하지 않는 환경에서도 같은 디자인 토큰과 인터페이스를 활용할 수 있도록 CSS class 기반 vanilla output을 함께 제공했습니다.
NPM 배포는 npm v11+의 auto-OIDC Trusted Publisher 방식으로 전환했습니다. Workflow에서 npm 버전을 명시적으로 올리고 NODE_AUTH_TOKEN과 registry token 의존성을 제거해 장기 credential 없이 패키지를 배포할 수 있도록 정리했습니다.
디자인 시스템은 개별 UI 컴포넌트를 제공하는 패키지에서 제품 화면을 조립하고 동일한 기준으로 검증·배포할 수 있는 인터페이스 기반으로 확장되었습니다. 현재 40개 이상의 공개 컴포넌트와 11개 디자인 토큰 도메인을 제공하며, 68개의 Storybook story 파일을 통해 컴포넌트의 상태와 조합을 검증할 수 있습니다.
제품 개발자는 layout primitive와 responsive navigation을 통해 반복적인 화면 구조를 직접 구현할 필요가 줄었고, polymorphic component API와 element별 disabled semantics를 통해 잘못된 속성 조합이나 접근성 오류가 발생할 여지를 API 수준에서 줄였습니다.
모션은 컴포넌트마다 관리하던 CSS animation과 별도 lifecycle state에서 공통 spring presence pattern으로 정리했습니다. Storybook과 테스트 환경도 실제 제품 렌더링과 animation lifecycle을 고려하도록 구성해 UI 변경을 더 일관된 조건에서 검증할 수 있게 했습니다.
배포에서는 React package와 vanilla output을 함께 제공해 서로 다른 제품 스택이 동일한 디자인 기준을 공유할 수 있도록 했고, NPM Trusted Publisher 전환을 통해 장기 publish token 없이 릴리즈할 수 있는 구조를 구축했습니다.
디자인 토큰·테마, 컴포넌트 API, 반응형 레이아웃, 접근성, 테스트·Storybook, NPM 릴리즈
Design tokens · Component API · Accessibility · Release system
React · TypeScript · SCSS · CSS Custom Properties · Storybook · Vitest · Rollup · react-spring · NPM Trusted Publisher
공개 GitHub 저장소와 NPM 패키지에서 재현 가능한 수치만 사용했습니다.