Bigtablet Design System UI Components
npm install @bigtablet/design-system


Bigtablet의 공식 디자인 시스템으로, Foundation(디자인 토큰)과 Components(UI 컴포넌트)로 구성된 통합 UI 라이브러리입니다.
---
- 주요 특징
- 설치
- 빠른 시작
- Vanilla JS (HTML/CSS/JS)
- 컴포넌트
- Foundation (디자인 토큰)
- 개발 가이드
- 기여하기
---
- React 19 지원 - 최신 React 버전 완벽 지원
- TypeScript - 완전한 타입 안정성
- Pure React / Next.js - 프레임워크별 최적화된 번들 제공
- Vanilla JS - Thymeleaf, JSP 등 서버 템플릿 지원
- 디자인 토큰 - 일관된 색상, 타이포그래피, 간격 시스템
- 접근성(a11y) - 키보드 네비게이션, 스크린 리더 호환
- Storybook - 인터랙티브 문서화
---
``bashnpm
npm install @bigtablet/design-system
$3
`bash
npm install react react-dom lucide-react react-toastify
`---
빠른 시작
$3
`tsx
import { Button, TextField } from '@bigtablet/design-system';
import '@bigtablet/design-system/style.css';function App() {
return (
);
}
`$3
`tsx
import { Sidebar, Button } from '@bigtablet/design-system/next';
import '@bigtablet/design-system/style.css';export default function Layout({ children }) {
return (
items={[
{ label: '홈', href: '/' },
{ label: '대시보드', href: '/dashboard' }
]}
/>
{children}
);
}
`---
Vanilla JS (HTML/CSS/JS)
React 없이 Thymeleaf, JSP, PHP 등 서버 템플릿 환경에서 사용할 수 있습니다.
`html
``html
`---
컴포넌트
$3
#### Button
`tsx
import { Button } from '@bigtablet/design-system';// 기본 사용
// Variants
// Sizes
// 너비 조절
`| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
variant | 'primary' \| 'secondary' \| 'ghost' \| 'danger' | 'primary' | 버튼 스타일 |
| size | 'sm' \| 'md' \| 'lg' | 'md' | 버튼 크기 |
| width | string | '100%' | 버튼 너비 |
| disabled | boolean | false | 비활성화 |#### Select
`tsx
import { Select } from '@bigtablet/design-system';const options = [
{ value: 'apple', label: '사과' },
{ value: 'banana', label: '바나나' },
{ value: 'orange', label: '오렌지', disabled: true },
];
// 기본 사용
label="과일 선택"
options={options}
placeholder="선택하세요"
onChange={(value, option) => console.log(value, option)}
/>
// Controlled
const [fruit, setFruit] = useState(null);
options={options}
value={fruit}
onChange={(value) => setFruit(value)}
/>
// Variants & Sizes
`| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
options | SelectOption[] | required | 옵션 목록 |
| value | string \| null | - | 선택된 값 (controlled) |
| defaultValue | string \| null | null | 기본 선택값 |
| onChange | (value, option) => void | - | 변경 핸들러 |
| placeholder | string | 'Select…' | 플레이스홀더 |
| variant | 'outline' \| 'filled' \| 'ghost' | 'outline' | 스타일 |
| size | 'sm' \| 'md' \| 'lg' | 'md' | 크기 |
| fullWidth | boolean | false | 전체 너비 |
| disabled | boolean | false | 비활성화 |---
$3
#### TextField
`tsx
import { TextField } from '@bigtablet/design-system';// 기본 사용
// 상태 표시
// 아이콘
import { Search, Eye } from 'lucide-react';
} placeholder="검색..." />
} type="password" />
// Variants
// 값 변환 (자동 포맷팅)
label="전화번호"
transformValue={(v) => v.replace(/\D/g, '').slice(0, 11)}
onChangeAction={(value) => console.log(value)}
/>
`| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
label | string | - | 라벨 |
| helperText | string | - | 도움말 텍스트 |
| error | boolean | false | 에러 상태 |
| success | boolean | false | 성공 상태 |
| variant | 'outline' \| 'filled' \| 'ghost' | 'outline' | 스타일 |
| size | 'sm' \| 'md' \| 'lg' | 'md' | 크기 |
| leftIcon | ReactNode | - | 왼쪽 아이콘 |
| rightIcon | ReactNode | - | 오른쪽 아이콘 |
| fullWidth | boolean | false | 전체 너비 |
| onChangeAction | (value: string) => void | - | 값 변경 콜백 |
| transformValue | (value: string) => string | - | 값 변환 함수 |#### DatePicker
`tsx
import { DatePicker } from '@bigtablet/design-system';// 기본 사용 (연-월-일)
const [date, setDate] = useState('');
label="생년월일"
value={date}
onChange={setDate}
/>
// 연-월 모드
label="시작 월"
mode="year-month"
value={date}
onChange={setDate}
/>
// 범위 제한
label="예약일"
startYear={2020}
endYear={2030}
selectableRange="until-today" // 오늘까지만 선택 가능
value={date}
onChange={setDate}
/>
// 너비 조절
`| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
label | string | - | 라벨 |
| value | string | - | 선택된 날짜 ('YYYY-MM-DD' 또는 'YYYY-MM') |
| onChange | (value: string) => void | required | 변경 핸들러 |
| mode | 'year-month' \| 'year-month-day' | 'year-month-day' | 날짜 선택 모드 |
| startYear | number | 1950 | 시작 연도 |
| endYear | number | 현재년도 + 10 | 종료 연도 |
| selectableRange | 'all' \| 'until-today' | 'all' | 선택 가능 범위 |
| minDate | string | - | 최소 날짜 |
| width | number \| string | '100%' | 너비 |
| disabled | boolean | false | 비활성화 |#### Checkbox
`tsx
import { Checkbox } from '@bigtablet/design-system';// 기본 사용
// Controlled
const [checked, setChecked] = useState(false);
label="알림 받기"
checked={checked}
onChange={(e) => setChecked(e.target.checked)}
/>
// Indeterminate (부분 선택)
// Sizes
`| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
label | ReactNode | - | 라벨 |
| size | 'sm' \| 'md' \| 'lg' | 'md' | 크기 |
| indeterminate | boolean | false | 부분 선택 상태 |
| checked | boolean | - | 체크 상태 |
| disabled | boolean | false | 비활성화 |#### Radio
`tsx
import { Radio } from '@bigtablet/design-system';const [selected, setSelected] = useState('option1');
name="options"
value="option1"
label="옵션 1"
checked={selected === 'option1'}
onChange={(e) => setSelected(e.target.value)}
/>
name="options"
value="option2"
label="옵션 2"
checked={selected === 'option2'}
onChange={(e) => setSelected(e.target.value)}
/>
`#### Switch
`tsx
import { Switch } from '@bigtablet/design-system';// 기본 사용
console.log(checked)} />
// Controlled
const [isOn, setIsOn] = useState(false);
// Sizes
`| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
checked | boolean | - | 켜짐 상태 (controlled) |
| defaultChecked | boolean | false | 기본 상태 |
| onChange | (checked: boolean) => void | - | 변경 핸들러 |
| size | 'sm' \| 'md' \| 'lg' | 'md' | 크기 |
| disabled | boolean | false | 비활성화 |#### FileInput
`tsx
import { FileInput } from '@bigtablet/design-system'; label="파일 선택"
accept="image/*"
onFiles={(files) => console.log(files)}
/>
// 여러 파일
label="이미지 업로드"
accept="image/*"
multiple
onFiles={(files) => console.log(files)}
/>
`| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
label | string | '파일 선택' | 버튼 라벨 |
| accept | string | - | 허용 파일 타입 |
| onFiles | (files: FileList \| null) => void | - | 파일 선택 핸들러 |
| multiple | boolean | false | 다중 선택 |
| disabled | boolean | false | 비활성화 |---
$3
#### Alert
`tsx
import { AlertProvider, useAlert } from '@bigtablet/design-system';// App에 Provider 추가
function App() {
return (
);
}
// 사용
function YourComponent() {
const { showAlert } = useAlert();
const handleDelete = () => {
showAlert({
variant: 'warning',
title: '삭제 확인',
message: '정말 삭제하시겠습니까?',
showCancel: true,
confirmText: '삭제',
cancelText: '취소',
onConfirm: () => console.log('삭제됨'),
onCancel: () => console.log('취소됨'),
});
};
return ;
}
`| Option | Type | Default | Description |
|--------|------|---------|-------------|
|
variant | 'info' \| 'success' \| 'warning' \| 'error' | 'info' | 알림 타입 |
| title | ReactNode | - | 제목 |
| message | ReactNode | - | 메시지 |
| confirmText | string | '확인' | 확인 버튼 텍스트 |
| cancelText | string | '취소' | 취소 버튼 텍스트 |
| showCancel | boolean | false | 취소 버튼 표시 |
| actionsAlign | 'left' \| 'center' \| 'right' | 'right' | 버튼 정렬 |
| onConfirm | () => void | - | 확인 핸들러 |
| onCancel | () => void | - | 취소 핸들러 |#### Toast
`tsx
import { ToastProvider, useToast } from '@bigtablet/design-system';// App에 Provider 추가
function App() {
return (
<>
>
);
}
// 사용
function YourComponent() {
const toast = useToast();
return (
);
}
`#### Spinner
`tsx
import { Spinner } from '@bigtablet/design-system'; // 기본 (24px)
// 작은 크기
// 큰 크기
`#### TopLoading
`tsx
import { TopLoading } from '@bigtablet/design-system';// Indeterminate (무한 로딩)
// Progress (진행률 표시)
// 커스텀 스타일
// 숨기기
`| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
isLoading | boolean | true | 표시 여부 |
| progress | number | - | 진행률 (0-100), 없으면 indeterminate |
| color | string | primary | 로딩바 색상 |
| height | number | 3 | 로딩바 높이 (px) |---
$3
#### Pagination
`tsx
import { Pagination } from '@bigtablet/design-system';const [page, setPage] = useState(1);
page={page}
totalPages={20}
onChange={setPage}
/>
`| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
page | number | required | 현재 페이지 |
| totalPages | number | required | 전체 페이지 수 |
| onChange | (page: number) => void | required | 페이지 변경 핸들러 |#### Sidebar (Next.js)
`tsx
import { Sidebar } from '@bigtablet/design-system/next';
import { Home, Settings, Users } from 'lucide-react';const items = [
{ href: '/', label: '홈', icon: Home },
{ href: '/users', label: '사용자', icon: Users },
{
type: 'group',
id: 'settings',
label: '설정',
icon: Settings,
children: [
{ href: '/settings/profile', label: '프로필' },
{ href: '/settings/security', label: '보안' },
],
},
];
items={items}
activePath={pathname}
match="startsWith"
brandHref="/main"
/>
`| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
items | SidebarItem[] | [] | 메뉴 아이템 |
| activePath | string | - | 현재 활성 경로 |
| match | 'startsWith' \| 'exact' | 'startsWith' | 경로 매칭 방식 |
| brandHref | string | '/main' | 로고 클릭 시 이동 경로 |
| onItemSelect | (href: string) => void | - | 아이템 선택 핸들러 |---
$3
#### Modal
`tsx
import { Modal } from '@bigtablet/design-system';const [isOpen, setIsOpen] = useState(false);
open={isOpen}
onClose={() => setIsOpen(false)}
title="모달 제목"
width={600}
>
모달 내용입니다.
`| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
open | boolean | required | 열림 상태 |
| onClose | () => void | - | 닫기 핸들러 |
| title | ReactNode | - | 제목 |
| width | number \| string | 520 | 모달 너비 |
| closeOnOverlay | boolean | true | 오버레이 클릭 시 닫기 |---
$3
#### Card
`tsx
import { Card } from '@bigtablet/design-system';
카드 내용입니다.
// 스타일 옵션
내용
`| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
heading | ReactNode | - | 카드 제목 |
| shadow | 'none' \| 'sm' \| 'md' \| 'lg' | 'sm' | 그림자 |
| padding | 'none' \| 'sm' \| 'md' \| 'lg' | 'md' | 내부 여백 |
| bordered | boolean | false | 테두리 표시 |---
Foundation (디자인 토큰)
$3
`scss
@use "@bigtablet/design-system/scss/token" as token;.my-component {
color: token.$color_primary;
padding: token.$spacing_md;
border-radius: token.$radius_sm;
font-size: token.$font_size_base;
}
`$3
| Category | Examples |
|----------|----------|
| Colors |
$color_primary, $color_error, $color_text_primary |
| Spacing | $spacing_xs (4px), $spacing_sm (8px), $spacing_md (16px) |
| Typography | $font_size_sm, $font_size_base, $font_weight_medium |
| Radius | $radius_sm (4px), $radius_md (8px), $radius_lg (12px) |
| Shadows | $shadow_sm, $shadow_md, $shadow_lg |
| Z-Index | $z_dropdown, $z_modal, $z_toast |---
프로젝트 구조
`
src/
├── styles/
│ ├── ts/ # TypeScript 디자인 토큰
│ └── scss/ # SCSS 토큰 및 믹스인
├── ui/
│ ├── general/ # Button, Select
│ ├── form/ # TextField, Checkbox, Radio, Switch, DatePicker, FileInput
│ ├── feedback/ # Alert, Toast, Spinner, TopLoading
│ ├── navigation/ # Pagination, Sidebar
│ ├── overlay/ # Modal
│ └── display/ # Card
├── index.ts # Pure React 진입점
└── next.ts # Next.js 진입점
`---
개발 가이드
`bash
저장소 클론
git clone https://github.com/Bigtablet/bigtablet-design-system.git
cd bigtablet-design-system의존성 설치
pnpm installStorybook 실행
pnpm storybook빌드
pnpm build
`---
기여하기
1. Fork the repository
2. Create your feature branch (
git checkout -b feat/amazing-feature)
3. Commit your changes (git commit -m 'feat: add amazing feature')
4. Push to the branch (git push origin feat/amazing-feature)
5. Open a Pull Request to develop branch$3
| Label | Description |
|-------|-------------|
|
feat | 새로운 기능 |
| fix | 버그/코드 수정 |
| docs | 문서 수정 |
| style | 코드 스타일 변경 |
| config` | 설정 파일 수정 |---
---