UI 컴포넌트

IMPLEMENTATION CATALOG

33가지 UI 구성 요소를 직접 확인하세요

실제 화면에서 동작하는 예시와 구현 코드를 함께 제공합니다. 프로젝트 구현 검토와 화면 구성 협의에 필요한 상태, 크기, 사용 방식을 빠르게 확인할 수 있습니다.

동작 예시구현 코드구현 검토용

1. 데이터 클래스 (Data Class)

설명

EasyObj와 EasyList는 템플릿 화면에서 반복되는 상태 조작을 단순화하는 데이터 헬퍼입니다. 객체/배열을 직접 다루는 문법을 유지하면서 React 렌더링과 상태 추적을 맞춥니다.

EasyObj

객체 상태를 프록시로 래핑해 중첩 속성 변경을 추적

EasyList

배열 상태에 push/pop/forAll 같은 조작 메서드 제공

forAll

목록 전체를 순회하며 각 항목을 직접 수정

toJS

프록시 상태를 순수 JavaScript 구조로 변환

EXAMPLE 1

EasyObj

프로필처럼 중첩된 객체 상태를 setter 없이 직접 갱신합니다.

EasyObj state

담당자 프로필

버튼을 눌러 중첩 객체와 배열 값을 직접 갱신합니다.

{
  "name": "김민준",
  "role": "Product Owner",
  "score": 82,
  "tags": [
    "온보딩",
    "우선순위"
  ],
  "address": {
    "city": "서울",
    "office": "강남 오피스"
  }
}
EasyObj는 중첩 객체와 배열 값을 직접 수정해도 화면 상태가 함께 갱신됩니다.
jsx
const dataObj = Lib.EasyObj({
    name: '김민준',
    score: 82,
    tags: ['온보딩', '우선순위'],
    address: {
        city: '서울',
        office: '강남 오피스'
    }
});

// 상태 변경 시 자동으로 리렌더링
dataObj.score += 5;
dataObj.tags.push('리뷰 완료');
dataObj.address.city = '부산';
EXAMPLE 2

EasyList

업무 목록처럼 반복되는 배열 상태를 CRUD 메서드로 다룹니다.

EasyList state

작업 큐

배열 메서드와 forAll로 항목을 조작합니다.

[
  {
    "id": 1,
    "text": "고객 문의 확인",
    "status": "진행 중"
  },
  {
    "id": 2,
    "text": "상담 일정 안내",
    "status": "대기"
  }
]
EasyList는 배열 메서드와 forAll을 사용해 목록 항목을 한 번에 조작합니다.
jsx
const taskList = Lib.EasyList([
    { id: 1, text: '고객 문의 확인', status: '진행 중' },
    { id: 2, text: '상담 일정 안내', status: '대기' }
]);

// 배열 메서드 사용
taskList.push({ id: 3, text: '추가 작업 3', status: '신규' });
taskList.pop();

// forAll 메서드로 모든 항목 수정
taskList.forAll(item => {
    item.status = '완료';
});

2. 버튼 (Button)

설명

Button은 사용자가 실행하는 핵심 동작을 표현합니다. 기본 variant를 유지하면서 상태, 크기, 아이콘, 로딩·비활성 상태를 일관된 밀도로 제공합니다.

children

버튼 내부 콘텐츠

variant?

primary, secondary, outline, danger 등 색상 스타일

size?

sm, md, lg 높이/패딩 밀도

icon?

Icon 컴포넌트에 전달할 아이콘 이름

iconPosition?

left 또는 right 아이콘 위치

loading?

처리 중 상태와 스피너 표시

disabled?

비활성 상태

type?

button, submit, reset

EXAMPLE 1

버튼 종류

업무 화면에서 쓰는 주요 CTA, 보조, 위험, 성공 액션을 한 줄로 비교합니다.

가장 중요한 기본 CTA

jsx
<Lib.Button icon="md:MdAdd">새 작업</Lib.Button>

보조 액션

jsx
<Lib.Button variant="secondary">임시저장</Lib.Button>

강조도를 낮춘 액션

jsx
<Lib.Button variant="outline">미리보기</Lib.Button>

배경이 없는 보조 액션

jsx
<Lib.Button variant="ghost">취소</Lib.Button>

파괴적 액션

jsx
<Lib.Button variant="danger" icon="md:MdDelete">삭제</Lib.Button>

성공/승인 액션

jsx
<Lib.Button variant="success" icon="md:MdCheck">승인</Lib.Button>

주의가 필요한 액션

jsx
<Lib.Button variant="warning" icon="md:MdWarning">확인 필요</Lib.Button>

텍스트 링크형 액션

jsx
<Lib.Button variant="link" icon="md:MdOpenInNew" iconPosition="right">자세히 보기</Lib.Button>

Dark 버튼

jsx
<Lib.Button variant="dark">관리자 실행</Lib.Button>
EXAMPLE 2

크기와 상태

sm/md/lg 크기와 icon/loading/disabled 상태를 한 화면에서 확인합니다.

테이블 행과 compact toolbar에 맞는 sm

jsx
<Lib.Button size="sm">Small</Lib.Button>

기본 폼 액션에 맞는 md + 아이콘

jsx
<Lib.Button size="md" icon="ri:RiSearchLine">검색</Lib.Button>

강조 CTA에 맞는 lg

jsx
<Lib.Button size="lg">Large</Lib.Button>
처리중...

loading은 aria-busy와 상태 안내를 함께 제공

jsx
<Lib.Button loading>저장 중</Lib.Button>

비활성화 상태

jsx
<Lib.Button disabled>권한 없음</Lib.Button>

3. 아이콘 (Icon)

설명

Icon 컴포넌트는 react-icons 세트를 하나의 API로 연결합니다. 장식 아이콘은 decorative=true 기본값으로 스크린리더에서 숨깁니다. 의미 있는 아이콘은 decorative=false로 설정하면 role="img"가 적용되며, 라벨은 ariaLabel을 우선 사용하고 없으면 icon 문자열을 대체 라벨로 사용합니다.

icon

세트 prefix와 아이콘 이름. 예: md:MdHome

size?

아이콘 크기. 기본값 1em

color?

직접 색상 지정

ariaLabel?

의미 있는 아이콘의 우선 접근성 라벨

decorative?

기본 true는 스크린리더에서 숨김. false면 role=img와 라벨을 제공

className?

Tailwind 색상/크기 클래스

EXAMPLE 1

아이콘 사용 패턴

기본 아이콘, 상태 색상, 접근성 라벨을 한 번에 확인합니다.

홈 대시보드
md:MdHome

Material 아이콘과 크기 변형

jsx
// 기본 아이콘
<Lib.Icon icon="md:MdHome" size="24px" />

// 다양한 크기
<Lib.Icon icon="md:MdHome" size="16px" />  // 작은 크기
<Lib.Icon icon="md:MdHome" size="24px" />  // 기본 크기
<Lib.Icon icon="md:MdHome" size="32px" />  // 큰 크기
<Lib.Icon icon="md:MdHome" size="40px" />  // 더 큰 크기
완료
주의
실패

상태 색상과 함께 쓰는 Bootstrap 아이콘

jsx
// 색상이 있는 아이콘
<Lib.Icon icon="bs:BsCheckCircle" className="text-emerald-700" size="20px" />
<Lib.Icon icon="bs:BsExclamationCircle" className="text-amber-800" size="20px" />
<Lib.Icon icon="bs:BsXCircle" className="text-rose-700" size="20px" />
GitHub 저장소
ariaLabel 제공
의미 있는 아이콘은 decorative=ariaLabel을 함께 사용합니다.

접근성 라벨이 필요한 의미 있는 아이콘

jsx
<Lib.Icon
  icon="fi:FiGithub"
  size="22px"
  ariaLabel="GitHub 저장소"
  decorative={false}
/>

4. 입력 (Input)

설명

Input은 텍스트, 숫자, 검색, 비밀번호처럼 폼에서 가장 많이 반복되는 입력 요소입니다. EasyObj 데이터 연결과 외부 상태 제어를 모두 지원하고, 마스크·필터·오류 상태를 한 컴포넌트 안에서 처리합니다.

dataObj/dataKey?

EasyObj 상태와 필드 키를 연결하는 입력

value/defaultValue?

외부 상태 제어 또는 초기값 기반 입력

type?

text, email, password, number 등 HTML input 타입

filter?

허용 문자 범위를 정해 입력 전 단계에서 차단

mask?

전화번호·사업자번호처럼 고정 포맷으로 변환

maxDigits/maxDecimals?

number 입력의 정수부·소수부 자릿수 제한

prefix/suffix?

검색 아이콘, 단위, 통화 등 보조 표시

error?

오류 상태와 에러 메시지 표시

마스크 패턴: # 숫자, A 대문자, a 소문자, ? 영문, * 모든 문자

EXAMPLE 1

기본 입력

텍스트와 이메일처럼 가장 자주 쓰는 폼 입력을 업무 화면 밀도로 확인합니다.

일반 텍스트 필드와 placeholder 상태

가장 기본적인 텍스트 입력

jsx
<Lib.Input
    dataObj={inputDataObj}
    dataKey="projectName"
    placeholder="예: 고객 포털 리뉴얼"
/>

type=email을 그대로 전달

이메일 입력

jsx
<Lib.Input
    dataObj={inputDataObj}
    dataKey="email"
    type="email"
    placeholder="owner@example.com"
/>
EXAMPLE 2

마스크 입력

전화번호와 사업자번호처럼 형식이 정해진 값을 입력 중에 바로 정리합니다.

숫자 입력을 전화번호 포맷으로 표시

전화번호 마스킹

jsx
<Lib.Input
    dataObj={inputDataObj}
    dataKey="phone"
    mask="###-####-####"
    placeholder="010-1234-5678"
/>

고정 포맷 식별자 입력

사업자번호 마스킹

jsx
<Lib.Input
    dataObj={inputDataObj}
    dataKey="businessNo"
    mask="###-##-#####"
    placeholder="사업자번호 123-45-67890"
/>
EXAMPLE 3

필터/숫자 입력

숫자 자릿수 제한과 문자셋 필터를 같은 카드 안에서 비교합니다.

정수 10자리, 소수 2자리까지 허용

숫자 입력 (자리수 제한)

jsx
<Lib.Input
    dataObj={inputDataObj}
    dataKey="amount"
    type="number"
    maxDigits={10}
    maxDecimals={2}
    placeholder="1200000.00"
/>

영문/숫자만 허용

영문/숫자 필터

jsx
<Lib.Input
    dataObj={inputDataObj}
    dataKey="code"
    filter="A-Za-z0-9"
    placeholder="TEAM2026"
/>

한글 조합 입력을 유지하면서 필터링

한글 필터

jsx
<Lib.Input
    dataObj={inputDataObj}
    dataKey="koreanName"
    filter="가-힣"
    placeholder="홍길동"
/>
EXAMPLE 4

고급 기능

prefix, suffix, error, password toggle처럼 실제 폼에서 자주 필요한 상태입니다.

이메일 형식이 올바르지 않습니다

검증 실패 메시지를 인라인으로 표시

에러 상태

jsx
<Lib.Input
    dataObj={inputDataObj}
    dataKey="recoveryEmail"
    error="이메일 형식이 올바르지 않습니다"
    placeholder="wrong-email"
/>

우측 정렬과 suffix 단위 표시

금액 입력 (우측 정렬, 접미사 표시)

jsx
<Lib.Input
    dataObj={inputDataObj}
    dataKey="price"
    type="number"
    maxDigits={10}
    className="text-right"
    placeholder="금액 입력"
    suffix="원"
/>

prefix 아이콘으로 검색 목적을 빠르게 인지

아이콘이 있는 검색 입력

jsx
<Lib.Input
    dataObj={inputDataObj}
    dataKey="searchKeyword"
    prefix={<Lib.Icon icon="ri:RiSearchLine" className="h-5 w-5 text-slate-400" />}
    placeholder="이름, 이메일, 회사명 검색"
/>

togglePassword로 표시/숨김 전환

비밀번호 토글 기능

jsx
<Lib.Input
    dataObj={inputDataObj}
    dataKey="password"
    type="password"
    placeholder="비밀번호 입력"
    togglePassword
/>

5. 멀티라인 입력 (Textarea)

설명

Textarea는 긴 메모, 설명, 고객 응답처럼 줄바꿈을 보존해야 하는 텍스트 입력에 사용합니다. 데이터 연결, 외부 상태 제어, 한글 조합 입력, 오류 상태, 읽기 전용 상태를 같은 API로 처리합니다.

rows?

기본 노출 줄 수. 기본값 4

dataObj/dataKey?

EasyObj 필드와 textarea 값을 연결

value/defaultValue?

외부 상태 제어 또는 초기값 기반 입력

error?

aria-invalid와 오류 테두리 상태

onChange/onValueChange?

변경 이벤트와 값 전용 콜백

placeholder?

비어 있을 때 보여주는 안내 문구

disabled?

입력 불가 상태

readOnly?

값은 노출하지만 편집을 막는 상태

EXAMPLE 1

데이터 연결

EasyObj 필드와 긴 메모 값을 연결해 입력 즉시 상태를 확인합니다.

EasyObj 필드에 바로 연결된 긴 텍스트 입력

textDataObj.memo

고객 상담에서 필요한 화면과 우선 제공할 기능을 확인했습니다.

dataObj + dataKey로 긴 메모 상태를 직접 연결

jsx
const textDataObj = Lib.EasyObj({
  memo: '고객 상담에서 필요한 화면과 우선 제공할 기능을 확인했습니다.',
});

<Lib.Textarea
  id="textarea-bound-memo"
  dataObj={textDataObj}
  dataKey="memo"
  rows={4}
  placeholder="메모를 입력하세요"
/>
EXAMPLE 2

외부 상태 제어

value/onValueChange를 사용해 외부 React 상태와 동기화합니다.

React state를 단일 소스로 유지

value = 고객 요청에 따라 신청서 항목과 관리자 확인 절차를 정리했습니다.

value + onValueChange로 외부 상태와 동기화

jsx
const [textValue, setTextValue] = useState('고객 요청에 따라 신청서 항목과 관리자 확인 절차를 정리했습니다.');

<Lib.Textarea
  id="textarea-controlled-note"
  value={textValue}
  onValueChange={setTextValue}
  rows={3}
/>
EXAMPLE 3

검증/에러 상태

최소 글자 수처럼 사용자가 바로 복구할 수 있는 검증 메시지를 보여줍니다.

10자 미만이면 바로 오류 상태로 노출

10자 이상 입력해주세요

error prop과 aria-invalid를 사용한 즉시 검증

jsx
<Lib.Textarea
  id="textarea-error-reason"
  dataObj={textDataObj}
  dataKey="memo"
  rows={4}
  error={textDataObj.memo.length < 10}
  placeholder="10자 이상 입력"
/>
<div className="mt-1 text-xs text-red-600">{textDataObj.memo.length < 10 ? '10자 이상 입력해주세요' : '정상'}</div>
EXAMPLE 4

읽기 전용/비활성

편집 불가 상태와 disabled 상태를 같은 표면에서 비교합니다.

readOnly와 disabled 상태를 나란히 비교

jsx
<Lib.Textarea
  id="textarea-readonly"
  value="검토 완료되어 더 이상 수정할 수 없습니다."
  readOnly
/>
<Lib.Textarea
  id="textarea-disabled"
  placeholder="관리자 권한이 필요합니다"
  disabled
/>

6. 선택 (Select)

설명

Select는 짧은 옵션 목록에서 하나의 값을 고르는 입력 요소입니다. EasyList의 selected 플래그, EasyObj 데이터 연결, 외부 상태 제어를 모두 지원하고 상태 메시지와 aria-live 안내를 함께 제공합니다.

dataList

옵션 배열 또는 EasyList. selected 플래그 동기화

valueKey/textKey?

옵션 값과 라벨로 사용할 키

dataObj/dataKey?

EasyObj 선택 값과 연결

value/onValueChange?

외부 상태의 선택 값과 동기화

status?

default, success, info, warning, error, loading, empty

statusMessage?

상태별 가시 안내 문구

assistiveText?

스크린리더용 보조 안내

disabled?

선택 불가 상태

EXAMPLE 1

기본 사용법

EasyList selected 플래그와 외부 상태 값을 실제 직무 선택 흐름으로 비교합니다.

dataList 내부 selected 플래그를 단일 선택으로 유지

dataList의 selected 플래그와 동기화됩니다.

현재 선택된 id
선택 전

EasyList 모드 — dataList 내부의 selected 플래그만으로 선택 상태를 관리

jsx
const jobOptionList = Lib.EasyList([
  { id: '', label: '담당 역할 선택', placeholder: true, selected: true },
  { id: 'designer', label: '프로덕트 디자이너' },
  { id: 'developer', label: '프론트엔드 개발자' },
  { id: 'pm', label: '프로덕트 매니저' },
]);

<Lib.Select
  id="select-easylist"
  dataList={jobOptionList}
  valueKey="id"
  textKey="label"
  status="success"
  statusMessage="dataList의 selected 플래그와 동기화됩니다."
/>

value prop을 외부 상태와 동기화

value prop: review

value = review

외부 상태 제어 — value/onValueChange로 선택값을 동기화하고 dataList.selected도 자동 갱신

jsx
const [roleValue, setRoleValue] = useState('review');

<Lib.Select
  id="select-controlled"
  dataList={jobOptionList}
  valueKey="id"
  textKey="label"
  value={roleValue}
  onValueChange={setRoleValue}
  status="info"
  statusMessage={`value prop: ${roleValue}`}
/>
EXAMPLE 2

상태

loading, error, empty처럼 사용자가 판단해야 하는 상태를 한 표면에서 확인합니다.

불러오는 중…옵션을 불러오는 중입니다.

로딩/비활성화 상태 — status="loading" + assistiveText로 라이브 영역 안내

jsx
<Lib.Select
  id="select-loading"
  dataList={loadingOptionList}
  valueKey="id"
  textKey="label"
  status="loading"
  assistiveText="옵션을 불러오는 중입니다."
  disabled
/>

필수 입력 항목입니다.

에러 상태 — status="error"와 안내 메시지

jsx
<Lib.Select
  id="select-error"
  dataList={jobOptionList}
  valueKey="id"
  textKey="label"
  status="error"
  statusMessage="필수 입력 항목입니다."
/>

표시할 항목이 없습니다.선택 가능한 항목이 비어 있습니다.

빈 상태 — status="empty" 프리셋으로 항목 부재 안내 및 aria-live=assertive 적용

jsx
<Lib.Select
  id="select-empty"
  dataList={Lib.EasyList([])}
  status="empty"
  assistiveText="선택 가능한 항목이 비어 있습니다."
/>

7. 체크박스 (Checkbox)

설명

Checkbox는 약관 동의, 알림 수신, 체크리스트처럼 여러 항목을 독립적으로 켜고 끄는 입력입니다. EasyObj 데이터 연결과 외부 상태 제어를 모두 지원하며, 색상 프리셋으로 상태 의미를 함께 전달할 수 있습니다.

label?

입력 옆에 노출되는 라벨 텍스트

name?

폼 제출·그룹 식별용 이름. 없으면 dataKey 또는 label 사용

dataObj/dataKey?

EasyObj 필드와 체크 상태를 양방향으로 연결

checked/onValueChange?

외부 상태로 체크 여부를 제어

color?

primary, success, warning, danger, neutral 프리셋

disabled?

읽기 전용·권한 부족 상태의 비활성화 표시

className?

문서/폼 레이아웃에 맞춘 추가 클래스

연결된 값은 boolean, Y, 1 계열을 체크 상태로 해석합니다.

EXAMPLE 1

기본 사용법

단일 체크와 EasyObj 데이터 연결을 설정·권한 화면에 가까운 밀도로 확인합니다.

알림 수신 설정

EasyObj boolean 필드에 각 항목을 독립 저장

EasyObj 데이터 연결 — 알림 설정처럼 여러 boolean 필드를 독립적으로 저장

jsx
const notificationDataObj = Lib.EasyObj({
  securityNotice: true,
  productNotice: false,
  marketingNotice: false,
});

<Lib.Checkbox
  name="notice"
  label="보안 알림 받기"
  dataObj={notificationDataObj}
  dataKey="securityNotice"
  color="danger"
/>
확인 대기

외부 상태 제어 — checked/onValueChange로 확인 상태와 동기화

jsx
const [isApproved, setIsApproved] = useState(false);

<Lib.Checkbox
  label="상담 내용 확인 완료"
  checked={isApproved}
  onValueChange={setIsApproved}
  color="success"
/>

권한이 없는 항목은 라벨까지 흐리게 처리됩니다.

비활성화 상태 — 권한 부족 또는 읽기 전용 항목 표시

jsx
<Lib.Checkbox
  label="관리자 전용 설정"
  disabled
/>
EXAMPLE 2

상태와 업무 시나리오

필수 약관, 알림 옵션, 상태 색상처럼 실제 폼에서 반복되는 선택 패턴입니다.

가입 약관 동의

약관 동의 — 필수/선택 항목을 같은 폼 그룹에서 관리

jsx
<Lib.Checkbox
  name="terms"
  label="[필수] 서비스 이용약관 동의"
  dataObj={consentDataObj}
  dataKey="termsAgreed"
  color="success"
/>

상태 색상 — success/warning/danger 프리셋으로 의미를 구분

jsx
<Lib.Checkbox
  label="요청 내용 확인"
  dataObj={checklistDataObj}
  dataKey="requestChecked"
  color="success"
/>
<Lib.Checkbox
  label="전화 상담 필요"
  dataObj={checklistDataObj}
  dataKey="callbackNeeded"
  color="warning"
/>

8. 체크버튼 (CheckButton)

설명

CheckButton은 Checkbox의 토글 동작을 버튼 UI로 보여주는 컴포넌트입니다. 일반 체크박스보다 클릭 면적이 넓어 필터 칩, 보기 설정, 작업 옵션처럼 빠르게 켜고 끄는 UI에 적합합니다.

children

버튼 내부 라벨 또는 아이콘+텍스트 콘텐츠

name?

폼 이름. 없으면 dataKey 또는 문자열 children 사용

dataObj/dataKey?

EasyObj boolean 필드와 토글 상태를 연결

checked/onValueChange?

외부 상태로 눌림 상태를 제어

color?

primary, success, warning, danger, neutral 프리셋

disabled?

선택 불가 상태와 커서/투명도 처리

className?

툴바·필터 영역에 맞춘 간격/폭 보정

aria-pressed로 현재 눌림 상태를 전달하므로 버튼형 토글 의미가 보조기술에도 유지됩니다.

EXAMPLE 1

기본 사용법

칩/토글 버튼처럼 클릭 면적이 필요한 체크 입력을 확인합니다.

업무 목록 필터

여러 필터를 동시에 토글하는 칩 UI

EasyObj 데이터 연결 — 필터 칩 여러 개를 독립적으로 켜고 끄는 패턴

jsx
const filterDataObj = Lib.EasyObj({
  unreadOnly: true,
  assignedToMe: false,
  highPriority: false,
});

<Lib.CheckButton dataObj={filterDataObj} dataKey="unreadOnly">
  읽지 않음
</Lib.CheckButton>
<Lib.CheckButton dataObj={filterDataObj} dataKey="assignedToMe" color="success">
  내 담당
</Lib.CheckButton>

현재 목록 밀도: 압축

외부 상태 제어 — checked/onValueChange로 보기 설정을 동기화

jsx
const [isCompactMode, setIsCompactMode] = useState(true);

<Lib.CheckButton
  checked={isCompactMode}
  onValueChange={setIsCompactMode}
>
  압축 보기
</Lib.CheckButton>

비활성화 상태 — 권한 부족이나 잠긴 옵션을 버튼 표면으로 표시

jsx
<Lib.CheckButton disabled>
  권한 없음
</Lib.CheckButton>
<Lib.CheckButton disabled color="danger">
  잠긴 액션
</Lib.CheckButton>
EXAMPLE 2

상태와 필터 패턴

업무 필터, 보기 설정, 상태 프리셋을 버튼형 선택으로 구성합니다.

상태 프리셋 — success/warning/danger/neutral 버튼 색상

jsx
<Lib.CheckButton color="success" dataObj={statusDataObj} dataKey="ready">
  Ready
</Lib.CheckButton>
<Lib.CheckButton color="warning" dataObj={statusDataObj} dataKey="pending">
  Pending
</Lib.CheckButton>
<Lib.CheckButton color="danger" dataObj={statusDataObj} dataKey="blocked">
  Blocked
</Lib.CheckButton>

9. 라디오박스 (Radiobox)

설명

Radiobox는 여러 선택지 중 하나만 고르는 기본 라디오 입력입니다. 같은 name을 공유하는 선택지는 하나의 그룹으로 동작하고, 선택된 value가 EasyObj 필드 또는 변경 콜백으로 전달됩니다.

label?

라디오 입력 옆에 표시되는 선택지 텍스트

name?

동일 그룹을 묶는 이름. 같은 name 안에서 하나만 선택

value

선택 시 dataObj 또는 onValueChange로 전달할 값

dataObj/dataKey?

EasyObj 단일 필드에 선택 value 저장

checked/defaultChecked?

외부에서 제어하는 상태 또는 초기 선택값

onValueChange?

선택된 value를 직접 받는 변경 핸들러

color?

primary, success, warning, danger, neutral 프리셋

disabled?

선택 불가 상태의 입력과 라벨 비활성화

버튼형 선택이 필요하면 같은 계약의 RadioButton을 사용합니다.

EXAMPLE 1

기본 사용법

라벨형 단일 선택을 역할·요금제 같은 실제 폼 패턴으로 확인합니다.

요금제 선택

선택된 value가 selectedPlan 필드에 저장됩니다.

EasyObj 데이터 연결 — 같은 name 그룹의 선택 value를 단일 필드에 저장

jsx
const planDataObj = Lib.EasyObj({
  selectedPlan: 'growth',
});

<Lib.Radiobox
  name="plan"
  label="Growth"
  value="growth"
  dataObj={planDataObj}
  dataKey="selectedPlan"
  color="primary"
/>

priority = normal

외부 상태 제어 — checked/onValueChange로 단일 선택값을 동기화

jsx
const [priorityValue, setPriorityValue] = useState('normal');

<Lib.Radiobox
  name="priority"
  label="긴급"
  value="urgent"
  checked={priorityValue === 'urgent'}
  onValueChange={setPriorityValue}
  color="danger"
/>

정책상 바꿀 수 없는 설정은 disabled로 잠급니다.

비활성화 상태 — 정책상 바꿀 수 없는 단일 선택 항목 표시

jsx
<Lib.Radiobox
  name="lockedRegion"
  label="국내 리전"
  value="kr"
  disabled
  defaultChecked
/>
EXAMPLE 2

상태와 업무 시나리오

외부 상태 제어, 비활성화, 상태 색상까지 라디오 그룹 동작을 비교합니다.

상태 색상 — neutral/warning/success 프리셋으로 선택 의미 구분

jsx
<Lib.Radiobox
  name="publishStatus"
  label="검토 요청"
  value="review"
  dataObj={statusDataObj}
  dataKey="publishStatus"
  color="warning"
/>

10. 라디오버튼 (RadioButton)

설명

RadioButton은 Radiobox의 단일 선택 계약을 버튼형 UI로 보여줍니다. 세그먼트 컨트롤, 가격 주기, 보기 모드처럼 선택된 옵션을 버튼 표면에서 강하게 보여줘야 할 때 사용합니다.

children

버튼 안에 표시되는 선택지 라벨

name?

동일 그룹을 묶는 이름. 없으면 dataKey 또는 문자열 children 사용

value

선택 시 저장·전달되는 단일 값

dataObj/dataKey?

EasyObj 필드에 선택 value를 저장

checked/onValueChange?

외부 상태로 선택 버튼을 제어

color?

primary, success, warning, danger, neutral 프리셋

disabled?

선택 불가 버튼 상태

className?

버튼 그룹 간격·정렬 보정

실제 input[type=radio]는 시각적으로 숨기고 버튼 표면으로 상태를 표현합니다.

EXAMPLE 1

기본 사용법

세그먼트 버튼처럼 보이는 단일 선택 UI를 요금제·기간 선택으로 확인합니다.

결제 주기

버튼형 단일 선택으로 현재 선택을 강하게 표시

EasyObj 데이터 연결 — 결제 주기처럼 선택된 value를 단일 필드에 저장

jsx
const billingDataObj = Lib.EasyObj({
  billingCycle: 'annual',
});

<Lib.RadioButton
  name="billingCycle"
  value="annual"
  dataObj={billingDataObj}
  dataKey="billingCycle"
  color="success"
>
  연간 20% 할인
</Lib.RadioButton>

language = ko

외부 상태 제어 — checked/onValueChange로 선택값을 동기화

jsx
const [languageValue, setLanguageValue] = useState('ko');

<Lib.RadioButton
  name="language"
  value="ko"
  checked={languageValue === 'ko'}
  onValueChange={setLanguageValue}
>
  한국어
</Lib.RadioButton>

비활성화 상태 — 사용자가 선택할 수 없는 채널을 버튼으로 표시

jsx
<Lib.RadioButton
  name="releaseChannel"
  value="stable"
  disabled
>
  Stable
</Lib.RadioButton>
EXAMPLE 2

상태와 업무 시나리오

보기 모드, 언어, 우선순위처럼 눌림 상태가 명확해야 하는 선택 패턴입니다.

보기 모드 — neutral/default/warning 프리셋으로 단일 버튼 그룹 구성

jsx
<Lib.RadioButton
  name="viewMode"
  value="kanban"
  dataObj={viewModeDataObj}
  dataKey="mode"
>
  칸반
</Lib.RadioButton>

11. 스위치 (Switch)

설명

Switch는 설정, 권한, 알림처럼 즉시 켜고 끄는 boolean 입력입니다. role="switch"aria-checked를 포함하며 EasyObj 데이터 연결과 외부 상태 제어를 모두 지원합니다.

dataObj/dataKey?

EasyObj boolean 또는 Y/1 계열 값을 스위치 상태와 연결

checked/defaultChecked?

외부에서 제어하는 상태 또는 초기 ON/OFF 값

onChange/onValueChange?

토글 후 boolean 값과 연결 정보 전달

label?

스위치 오른쪽에 표시되는 짧은 라벨

disabled?

수정 불가 상태와 접근성 비활성 상태 표시

id/name?

라벨 연결, 폼 전송, 테스트 셀렉터에 사용할 식별자

className?

설정 행·카드 내부 배치에 맞춘 간격 보정

연결된 값은 true, Y, 1 계열을 ON으로 해석해 서버·폼 데이터와 함께 쓰기 쉽습니다.

EXAMPLE 1

기본 사용법

설정 화면에서 ON/OFF 값을 즉시 바꾸는 업무형 토글 패턴입니다.

주간 리포트 이메일

월요일 오전 9시에 팀 요약을 발송합니다.

settings.weeklyDigest = true

설정 객체와 dataKey를 직접 연결한 스위치

jsx
const switchDataObj = Lib.EasyObj({ weeklyDigest: true });

<Lib.Switch
  dataObj={switchDataObj}
  dataKey="weeklyDigest"
  label={switchDataObj.weeklyDigest ? 'ON' : 'OFF'}
/>
임시저장 자동화

입력 중인 초안을 30초마다 저장합니다.

isAutoSaveOn = false

외부 React state로 상태를 제어하는 스위치

jsx
const [isAutoSaveOn, setIsAutoSaveOn] = useState(false);

<Lib.Switch
  checked={isAutoSaveOn}
  onValueChange={(nextValue) => setIsAutoSaveOn(nextValue)}
  label={isAutoSaveOn ? '사용' : '중지'}
/>
EXAMPLE 2

상태와 접근성

비활성·초기값·id 연결처럼 실제 운영 화면에서 필요한 상태를 확인합니다.

보안 점검 모드
외부 공유 허용

disabled와 defaultChecked를 함께 사용한 잠긴 설정 상태

jsx
<Lib.Switch disabled defaultChecked label="비활성화" />
<Lib.Switch disabled label="비활성화 (OFF)" />

명시적인 id로 외부 라벨과 스위치를 연결합니다.

id를 지정해 외부 label과 스위치 입력을 명확하게 연결

jsx
<Lib.Switch
  dataObj={switchDataObj}
  dataKey="notifications"
  id="notify-switch"
  label="푸시 알림"
/>

12. 숫자 입력 (NumberInput)

설명

NumberInput은 직접 입력과 증감 버튼을 함께 제공하는 숫자 입력입니다. 입력을 벗어나는 시점에 값을 정규화하고, min/max 범위를 벗어나면 허용 범위로 보정합니다.

dataObj/dataKey?

EasyObj 숫자 필드와 입력 값을 양방향으로 연결

value/defaultValue?

외부에서 제어하는 값 또는 독립형 초기 숫자

min/max?

입력·증감 버튼으로 확정되는 허용 범위

step?

버튼·키보드 증감 단위. 기본값은 1

onChange/onValueChange?

확정된 숫자 또는 빈 값과 연결 정보 전달

disabled/readOnly?

입력 및 증감 버튼을 잠그는 상태

placeholder/id?

빈 값 안내 문구와 접근성 식별자

className?

카드/폼 행 안에서 폭과 간격을 보정

키보드 ArrowUp/ArrowDownPageUp/PageDown도 step 단위로 동작해 데이터 입력 화면에서 빠르게 값을 조정할 수 있습니다.

EXAMPLE 1

기본

수량처럼 최소값과 step 1이 필요한 가장 기본적인 숫자 입력입니다.

form.seatCount = 3

좌석 수처럼 최소·최대 범위가 있는 기본 데이터 연결 숫자 입력

jsx
const numberDataObj = Lib.EasyObj({ seatCount: 3 });

<Lib.NumberInput
  id="number-seat-count"
  dataObj={numberDataObj}
  dataKey="seatCount"
  min={1}
  max={20}
  step={1}
/>
EXAMPLE 2

범위와 스텝

예산·비율처럼 min/max와 소수 step을 함께 쓰는 케이스입니다.

0.5% 단위로 0~50% 범위 안에서 조정합니다.

소수 step을 쓰는 비율 입력과 min/max 보정

jsx
<Lib.NumberInput
  id="number-discount-rate"
  dataObj={priceDataObj}
  dataKey="discountRate"
  min={0}
  max={50}
  step={0.5}
/>
EXAMPLE 3

독립형

간단한 초기값 입력이나 독립 위젯으로 사용할 때의 형태입니다.

간단한 독립 입력으로 5일 단위 초기값을 제공합니다.

외부 state 연결 없이 defaultValue로 시작하는 독립 숫자 입력

jsx
<Lib.NumberInput id="number-report-cycle" defaultValue={10} min={5} step={5} />

13. 날짜/시간 (Date/Time)

설명

DateInput과 TimeInput은 텍스트 입력과 선택 도구를 함께 제공해 날짜·시간 값을 폼 문자열로 확정합니다. EasyObj 데이터 연결, 외부 상태 제어, 직접 입력 후 blur 또는 Enter로 확정하는 흐름을 지원합니다.

dataObj/dataKey?

EasyObj의 날짜 또는 시간 문자열 필드와 연결

value/defaultValue?

외부에서 제어하는 값 또는 초기 날짜·시간 값

min/max?

DateInput의 선택 가능 날짜 범위

step?

TimeInput 옵션 간격. 분 단위로 옵션 목록 생성

onChange/onValueChange?

확정된 문자열 값과 연결 정보 전달

disabled/readOnly?

직접 입력과 선택 버튼을 함께 잠금

placeholder/id?

입력 안내와 라벨 연결 식별자

className?

예약 폼, 필터 카드 등에서 폭을 보정

DateInput은 YYYY-MM-DD, TimeInput은 HH:mm 문자열을 확정 값으로 사용합니다.

EXAMPLE 1

날짜 입력

일정 시작일, 계약 기간처럼 날짜 문자열을 입력하고 달력으로 선택합니다.

schedule.startDate = 2026-07-15

프로젝트 시작일을 EasyObj 필드와 연결

jsx
const dateDataObj = Lib.EasyObj({ startDate: '2026-07-15' });

<Lib.DateInput
  id="date-start"
  dataObj={dateDataObj}
  dataKey="startDate"
/>

2026년 계약 기간 안에서만 선택하도록 제한합니다.

min/max와 defaultValue로 선택 가능 기간 제한

jsx
<Lib.DateInput
  id="date-contract-end"
  defaultValue="2026-12-31"
  min="2026-01-01"
  max="2026-12-31"
/>
EXAMPLE 2

시간 입력

예약 시간, 발송 시간처럼 고정 간격 옵션과 직접 입력을 함께 지원합니다.

notification.sendTime = 09:30

알림 발송 시간을 EasyObj 필드와 연결

jsx
const timeDataObj = Lib.EasyObj({ sendTime: '09:30' });

<Lib.TimeInput
  id="time-send"
  dataObj={timeDataObj}
  dataKey="sendTime"
  step={30}
/>

15분 단위 옵션으로 예약 시간을 선택합니다.

defaultValue와 15분 단위 옵션 목록

jsx
<Lib.TimeInput id="time-meeting" defaultValue="14:00" step={15} />

14. 콤보박스 (Combobox)

설명

검색 가능한 단일·다중 선택 입력입니다. dataListselected 값을 기반으로 선택 상태를 관리하며 초성 검색을 지원합니다.

  • dataList: 선택 항목 배열(EasyList 가능)
  • valueKey / textKey (선택): 값/라벨 키 (기본: 'value'/'text')
  • value?: 제어 값 (단일 또는 배열)
  • defaultValue?: 초기 선택 값
  • multi?: 다중 선택 모드
  • multiSummary?: 다중 선택 요약 배지 표시
  • summaryText?: 요약 배지 텍스트 템플릿
  • filterable?: 입력 검색 기능
  • placeholder?: 선택 전 표시 문구
  • noResultsText?: 검색 결과 없음 문구
  • showSelectAll?: 전체 선택/해제 버튼 표시
  • selectAllText?/clearAllText?: 전체 선택/해제 텍스트
  • onChange?/onValueChange?: 값 변경 콜백
  • className?: 추가 Tailwind 클래스
  • id?: input id 지정
  • disabled?: 비활성화 여부

기본

선택 도시: incheon

EasyObj 데이터 연결 — dataObj/dataKey로 주소 객체와 동기화
jsx
const cityList = Lib.EasyList([
  { value: 'seoul', text: '서울' },
  { value: 'busan', text: '부산' },
  { value: 'incheon', text: '인천' },
  { value: 'daegu', text: '대구' },
]);
const profileDataObj = Lib.EasyObj({ address: { city: 'incheon' } });

<Lib.Combobox
  dataList={cityList}
  dataObj={profileDataObj.address}
  dataKey="city"
  placeholder="도시 선택"
  status="success"
  statusMessage={`선택 도시: ${profileDataObj.address.city}`}
/>

데이터 연결

value prop: seoul

초성검색 예: ㅅㅇ→서울, ㅂㅅ→부산
외부 상태 제어 — value/onValueChange 조합
jsx
const [controlledCity, setControlledCity] = useState('seoul');

<Lib.Combobox
  dataList={cityList}
  value={controlledCity}
  onValueChange={setControlledCity}
  placeholder="도시 선택 (외부 상태 제어)"
  status="info"
  statusMessage={`value prop: ${controlledCity}`}
/>

다중 선택

다중 선택 (EasyList selected와 연결된 값 동시 반영)

다중 선택 + EasyObj 배열 연결 — favorites 배열과 EasyList selected 동기화
jsx
<Lib.Combobox
  dataList={cityList}
  dataObj={profileDataObj.address}
  dataKey="favorites"
  multi
  multiSummary
  showSelectAll
  summaryText="{count}개 도시 선택"
  placeholder="좋아하는 도시 선택"
  status="warning"
  statusMessage="다중 선택 (EasyList selected와 연결된 값 동시 반영)"
/>

상태 (로딩/빈 목록)

로딩

불러오는 중…도시 목록을 불러오는 중입니다.

로딩/비활성화 — status="loading" + assistiveText
jsx
<Lib.Combobox
  dataList={Lib.EasyList([{ value: '', text: '불러오는 중', placeholder: true }])}
  status="loading"
  assistiveText="도시 목록을 불러오는 중입니다."
  disabled
/>

빈 목록

표시할 항목이 없습니다.선택 가능한 도시가 없습니다.

빈 상태 — status="empty" 프리셋으로 항목 부재 안내와 assertive 라이브 영역
jsx
<Lib.Combobox
  dataList={Lib.EasyList([])}
  status="empty"
  assistiveText="선택 가능한 도시가 없습니다."
/>

16. 로딩 (Loading)

설명

전역 setLoading을 통해 전체 화면 로딩 오버레이를 표시합니다.

  • 별도 props 없이 중앙에 표시됩니다.

기본 사용

전체 화면 로딩 표시
jsx
const loadingTimerRef = useRef(null);
const { setLoading } = useGlobalUi();

/**
 * @description 전역 로딩 예제 타이머를 정리
 * 처리 규칙: 예제 컴포넌트가 사라지면 pending timeout을 취소한다.
 */
useEffect(() => () => clearTimeout(loadingTimerRef.current), []);

/**
 * @description 전역 로딩 버튼 클릭을 처리
 * 처리 규칙: 로딩 표시 후 2초 뒤 자동 해제한다.
 */
const handleLoadingClick = () => {
  setLoading(true);
  clearTimeout(loadingTimerRef.current);
  loadingTimerRef.current = setTimeout(() => setLoading(false), 2000);
};

<Lib.Button onClick={handleLoadingClick}>
  전체 화면 로딩 (2초)
</Lib.Button>

17. 알림 (Alert)

설명

전역 스토어(useGlobalUi)의 showAlert로 간단히 알림을 표시합니다.

정보/성공/경고/오류 유형을 지원하며 제목과 메시지를 지정할 수 있습니다.

  • title?: 알림 제목 (기본: '알림')
  • text: 표시 메시지
  • type?: 'info' | 'success' | 'warning' | 'error'
  • onClick?: 확인 버튼 클릭 콜백

기본 사용

기본 알림
jsx
// useSharedStore 사용
const { showAlert } = useGlobalUi();

// 기본 알림
showAlert('기본 알림 메시지입니다.');

알림 유형

알림 유형
jsx
// 정보/성공/경고/오류 알림
showAlert('정보 알림 메시지입니다.', { title: '정보', type: 'info' });
showAlert('성공 알림 메시지입니다.', { title: '성공', type: 'success' });
showAlert('경고 알림 메시지입니다.', { title: '경고', type: 'warning' });
showAlert('오류 알림 메시지입니다.', { title: '오류', type: 'error' });

콜백 함수

알림 닫힘 콜백
jsx
// 알림 닫힘 시 실행될 콜백
showAlert('작업이 완료되었습니다.', {
  title: '알림',
  onClick: function() {
    alert('알림을 닫았습니다.');
  }
});

포커스 이동

알림 닫힘 후 지정된 요소로 포커스 이동
jsx
// useRef 로 입력창 참조 생성
const inputRef = useRef(null);

// 알림을 닫으면 입력창으로 포커스 이동
<div className="flex gap-4 items-center">
  <Lib.Button
    onClick={() => {
      showAlert('알림을 닫히면 입력창으로 커서가 이동합니다.', {
        title: '알림',
        onFocus: () => inputRef.current?.focus(),
      });
    }}
  >
    알림 띄우기
  </Lib.Button>
  <Lib.Input ref={inputRef} placeholder="커서가 여기로 이동합니다" />
</div>

18. 확인 (Confirm)

설명

전역 스토어(useGlobalUi)의 showConfirm로 확인 대화상자를 띄웁니다.

Promise를 반환하며, 사용자의 선택(확인: true, 취소: false)을 then으로 받을 수 있습니다.

  • title?: 대화상자 제목
  • text: 표시 메시지
  • type?: 'info' | 'warning' | 'danger'
  • onConfirm?, onCancel?: 콜백
  • confirmText?, cancelText?: 버튼 텍스트

기본 사용

기본 확인 모달
jsx
// useSharedStore 사용
const { showConfirm, showAlert } = useGlobalUi();

// 기본 확인
showConfirm('정말 진행하시겠습니까?').then((result) => {
  if (result) showAlert('확인했습니다.');
});

확인 유형

확인 모달 유형
jsx
// 경고 확인
showConfirm('해당 작업은 되돌릴 수 없습니다.\n계속하시겠습니까?', {
  title: '주의',
  type: 'warning',
  confirmText: '계속',
  cancelText: '중단',
});

// 위험 확인
showConfirm('모든 데이터를 삭제합니다.\n정말 삭제하시겠습니까?', {
  title: '위험 확인',
  type: 'danger',
  confirmText: '삭제',
  cancelText: '취소',
});

콜백

확인/취소 콜백
jsx
// 확인/취소 시 실행될 콜백
showConfirm('삭제를 진행하시겠습니까?', {
  title: '위험 확인',
  type: 'danger',
  confirmText: '삭제',
  cancelText: '취소',
  onConfirm: () => showAlert('삭제가 완료되었습니다.'),
  onCancel: () => showAlert('삭제가 취소되었습니다.'),
});

포커스 이동

확인 모달 닫힘 후 포커스 이동
jsx
// useRef 로 입력창 참조 생성
const inputRef = useRef(null);

// 모달 닫힘 후 입력창으로 포커스 이동
<div className="flex gap-4 items-center">
  <Lib.Button
    onClick={() => {
      showConfirm('확인 모달이 닫히면 입력창으로 커서가 이동합니다.', {
        title: '포커스 이동',
        onFocus: () => inputRef.current?.focus(),
      });
    }}
  >
    포커스 이동 표시
  </Lib.Button>
  <Lib.Input ref={inputRef} placeholder="커서가 여기로 이동합니다" />
</div>

19. 토스트 (Toast)

설명

전역 스토어(useGlobalUi)의 showToast로 간단한 알림 배너를 표시합니다.

정보/성공/경고/오류 유형, 6가지 위치, 지속시간 제어를 지원합니다.

  • message: 표시 내용
  • type?: 'info' | 'success' | 'warning' | 'error'
  • position?: top/bottom - left/center/right
  • duration?: 자동 닫힘 시간(ms), Infinity로 무한

기본 사용

기본 토스트
jsx
// useSharedStore 사용
const { showToast } = useGlobalUi();

// 기본 토스트
showToast('기본 토스트 메시지입니다.');

토스트 유형

토스트 유형
jsx
showToast('정보 토스트 메시지입니다.', { type: 'info' });
showToast('성공 토스트 메시지입니다.', { type: 'success' });
showToast('경고 토스트 메시지입니다.', { type: 'warning' });
showToast('오류 토스트 메시지입니다.', { type: 'error' });

토스트 위치

토스트 위치
jsx
showToast('상단 왼쪽에 표시합니다.', { position: 'top-left' });
showToast('상단 중앙에 표시합니다.', { position: 'top-center' });
showToast('상단 오른쪽에 표시합니다.', { position: 'top-right' });
showToast('하단 왼쪽에 표시합니다.', { position: 'bottom-left' });
showToast('하단 중앙에 표시합니다.', { position: 'bottom-center' });
showToast('하단 오른쪽에 표시합니다.', { position: 'bottom-right' });

토스트 지속시간

토스트 유지 시간
jsx
showToast('2초에 사라집니다.', { duration: 2000 });
showToast('5초에 사라집니다.', { duration: 5000 });
showToast('자동으로 사라지지 않습니다.', { duration: Infinity });

20. 툴팁 (Tooltip)

설명

hover, focus 또는 클릭에 반응하는 간단한 툴팁입니다.

  • content: 툴팁 내용
  • placement?: 위치 'top' | 'bottom' | 'left' | 'right'
  • trigger?: 'hover' | 'click' | 'focus'
  • delay?: 표시 지연(ms)
  • disabled?: 비활성화 여부
  • textDirection?: 텍스트 방향 'lr' | 'tb'
  • className?: 추가 Tailwind 클래스
  • children?: 트리거 요소

기본

기본 사용 (hover/focus)
jsx
<Lib.Tooltip content="기본 툴팁">
  <Lib.Button>Hover</Lib.Button>
</Lib.Tooltip>

방향

placement: top/bottom/left/right
jsx
<Lib.Tooltip content="오른쪽" placement="right"><Lib.Button>right</Lib.Button></Lib.Tooltip>

트리거

trigger="click" 으로 클릭 시 표시
jsx
<Lib.Tooltip content="클릭" trigger="click"><Lib.Button>Click</Lib.Button></Lib.Tooltip>

21. 배지/태그 (Badge/Tag)

설명

Badge는 상태, 권한, 단계, 카테고리를 짧은 라벨로 표현하는 컴포넌트입니다. 채도가 낮은 slate·indigo 색상 위에서 과하게 튀지 않도록 색상과 밀도를 정돈합니다.

children

배지 내부에 표시할 텍스트 또는 아이콘

variant?

neutral, primary, success, warning, danger, outline

size?

sm 또는 md 크기 선택

pill?

완전히 둥근 pill 형태로 표시

className?

추가 Tailwind 클래스

EXAMPLE 1

상태별 표현

운영 화면에서 자주 쓰는 상태값을 색상별로 빠르게 구분합니다.

검토 대기신규 요청운영 정상확인 필요장애 발생
상태별 색상 Variant를 pill 형태로 정리
jsx
<Lib.Badge pill>검토 대기</Lib.Badge>
<Lib.Badge variant="primary" pill>신규 요청</Lib.Badge>
<Lib.Badge variant="success" pill>운영 정상</Lib.Badge>
<Lib.Badge variant="warning" pill>확인 필요</Lib.Badge>
<Lib.Badge variant="danger" pill>장애 발생</Lib.Badge>
EXAMPLE 2

Outline / Pill

강조도를 낮춘 보조 라벨과 둥근 상태 칩을 함께 보여줍니다.

읽기 전용보조 필터활성 조건
outline은 보조 라벨, pill은 필터/상태 칩에 적합
jsx
<Lib.Badge variant="outline">읽기 전용</Lib.Badge>
<Lib.Badge variant="outline" pill>보조 필터</Lib.Badge>
<Lib.Badge variant="primary" pill>활성 조건</Lib.Badge>
EXAMPLE 3

크기

테이블 안의 작은 라벨과 카드 상단의 중간 라벨을 분리해 사용합니다.

테이블 행완료
카드 헤더진행 중
sm은 밀도 높은 행, md는 카드/헤더 라벨에 사용
jsx
<Lib.Badge size="sm" variant="success" pill>완료</Lib.Badge>
<Lib.Badge size="md" variant="primary" pill>진행 중</Lib.Badge>
EXAMPLE 4

아이콘 포함

상태 의미가 중요한 곳에는 아이콘을 붙여 스캔 속도를 높입니다.

배포 완료

모든 smoke가 통과한 상태

검토중

리뷰 또는 QA 대기

차단됨

즉시 원인 확인 필요

아이콘을 포함해 상태 의미를 빠르게 스캔
jsx
<Lib.Badge variant="success" pill><Lib.Icon icon="md:MdCheck" /> 배포 완료</Lib.Badge>
<Lib.Badge variant="warning" pill><Lib.Icon icon="md:MdSchedule" /> 검토중</Lib.Badge>
<Lib.Badge variant="danger" pill><Lib.Icon icon="md:MdClose" /> 차단됨</Lib.Badge>

22. 지표 카드 (Stat)

설명

Stat은 대시보드와 관리 화면에서 핵심 KPI를 한눈에 보여주는 요약 카드입니다. 값, 증감, 아이콘, 도움말을 조합해 숫자형 지표와 상태형 지표를 같은 규칙으로 표시합니다.

label

지표 이름 또는 기준

value

강조 표시할 핵심 값

delta?

증감률 또는 상태 변화

deltaType?

up, down, neutral 변화 방향

icon?

우측 보조 아이콘 노드

helpText?

하단 보조 설명

className?

루트 추가 클래스

EXAMPLE 1

기본 KPI

가장 중요한 지표를 카드 한 장으로 명확하게 보여줍니다.

이번 주 활성 사용자
12,340
+3.2%
지난 7일 기준, 전주 대비
증가 지표를 아이콘과 도움말로 보강
jsx
<Lib.Stat
  label="이번 주 활성 사용자"
  value="12,340"
  delta="+3.2%"
  deltaType="up"
  helpText="지난 7일 기준, 전주 대비"
  icon={<Lib.Icon icon="ri:RiUserHeartLine" className="h-5 w-5 text-indigo-600" />}
/>
EXAMPLE 2

운영 지표 묶음

상승/하락/중립 지표를 같은 grid 안에서 비교합니다.

완료된 요청
1,024
+84
오늘 처리량
대기 시간
132ms
-18ms
평균 응답 시간
리뷰 대기
6건
동일
전일 대비 변화 없음
여러 KPI를 같은 grid 밀도로 배치
jsx
<div className="grid gap-3 md:grid-cols-3">
  <Lib.Stat label="완료된 요청" value="1,024" delta="+84" deltaType="up" />
  <Lib.Stat label="대기 시간" value="132ms" delta="-18ms" deltaType="down" />
  <Lib.Stat label="리뷰 대기" value="6건" delta="동일" deltaType="neutral" />
</div>
EXAMPLE 3

서비스 상태

값이 숫자가 아니어도 상태와 도움말을 함께 전달할 수 있습니다.

서비스 상태
정상
99.99%
최근 30일 가용성
상태형 값과 가용성 보조 텍스트 조합
jsx
<Lib.Stat
  label="서비스 상태"
  value="정상"
  delta="99.99%"
  deltaType="neutral"
  helpText="최근 30일 가용성"
  icon={<Lib.Icon icon="md:MdCloudDone" className="h-5 w-5 text-emerald-600" />}
/>

23. 스켈레톤 (Skeleton)

설명

Skeleton은 실제 데이터가 도착하기 전에도 화면의 구조와 밀도를 유지하는 로딩 플레이스홀더입니다. 목록, 프로필, 카드처럼 반복되는 패턴을 먼저 보여주면 레이아웃 흔들림이 줄어듭니다.

variant?

rect, text, circle 형태 선택

lines?

text variant의 라인 수

circleSize?

circle variant의 크기(px)

className?

높이, 너비, 여백 등 추가 클래스

EXAMPLE 1

텍스트 로딩

문단 또는 리스트가 로딩 중일 때 콘텐츠 밀도를 미리 보여줍니다.

문단과 보조 메타가 함께 로딩되는 텍스트 스켈레톤
jsx
<div className="space-y-3">
  <Lib.Skeleton variant="text" lines={3} />
  <Lib.Skeleton className="h-3 w-2/3 rounded-full" />
</div>
EXAMPLE 2

아바타 + 텍스트

프로필, 댓글, 활동 로그처럼 반복되는 행 구조에 사용합니다.

활동 로그나 담당자 목록처럼 반복되는 행 로딩 상태
jsx
<div className="flex items-center gap-3">
  <Lib.Skeleton variant="circle" circleSize={48} />
  <div className="flex-1 space-y-2">
    <Lib.Skeleton className="h-3 w-36 rounded-full" />
    <Lib.Skeleton className="h-3 w-2/3 rounded-full" />
  </div>
  <Lib.Skeleton className="h-6 w-16 rounded-full" />
</div>
EXAMPLE 3

카드 스켈레톤

대시보드 카드가 로딩 중일 때 최종 레이아웃을 안정적으로 유지합니다.

카드 내부 구조를 유지하는 대시보드 로딩 조합
jsx
<Lib.Card className="bg-white">
  <div className="flex items-center gap-3">
    <Lib.Skeleton variant="circle" circleSize={40} />
    <div className="flex-1 space-y-2">
      <Lib.Skeleton className="h-3 w-32 rounded-full" />
      <Lib.Skeleton className="h-3 w-24 rounded-full" />
    </div>
  </div>
  <div className="mt-5 grid gap-3 sm:grid-cols-3">
    <Lib.Skeleton className="h-16 w-full rounded-xl" />
    <Lib.Skeleton className="h-16 w-full rounded-xl" />
    <Lib.Skeleton className="h-16 w-full rounded-xl" />
  </div>
</Lib.Card>

24. 엠티 (Empty)

설명

Empty는 데이터가 없거나 필터 결과가 비었을 때 상황과 다음 행동을 안내합니다. 단순한 빈 화면이 아니라, 사용자가 복구하거나 새 항목을 만들 수 있는 방향을 함께 제시합니다.

icon?

상단 아이콘 이름

title?

비어 있는 상태 제목

description?

후속 행동을 안내하는 설명

children?

추가 안내 또는 보조 콘텐츠

action?

버튼 등 주요 액션 요소

className?

루트 추가 클래스

EXAMPLE 1

기본 Empty

목록이나 조회 결과가 비어 있을 때 간결한 안내를 제공합니다.

아직 등록된 항목이 없습니다

새 프로젝트를 만들거나 필터 조건을 조정하면 이 영역에 결과가 표시됩니다.

기본 Empty에 업무 맥락의 제목과 설명을 부여
jsx
<Lib.Empty
  icon="ri:RiInboxArchiveLine"
  title="아직 등록된 항목이 없습니다"
  description="새 프로젝트를 만들거나 필터 조건을 조정하면 이 영역에 결과가 표시됩니다."
/>
EXAMPLE 2

설명/액션

사용자가 다음 행동을 바로 선택할 수 있도록 CTA를 함께 배치합니다.

조건에 맞는 결과가 없습니다

검색어를 줄이거나 상태 필터를 전체로 바꿔 다시 확인해 보세요.

검색어: design상태: 대기
필터 결과 없음 상태에서 보조 정보와 액션을 함께 제공
jsx
<Lib.Empty
  icon="md:MdSearchOff"
  title="조건에 맞는 결과가 없습니다"
  description="검색어를 줄이거나 상태 필터를 전체로 바꿔 다시 확인해 보세요."
  action={<Lib.Button size="sm">새 항목 만들기</Lib.Button>}
>
  <Lib.Badge variant="outline" pill>검색어: design</Lib.Badge>
</Lib.Empty>

25. 카드 (Card)

설명

헤더, 본문, 푸터를 한 번에 묶는 기본 컨테이너 컴포넌트입니다. 대시보드 요약, 설정 패널, 동작 카드처럼 반복되는 정보 블록을 정돈된 흰색 카드로 표현합니다.

idtitle을 함께 전달하면 카드가 생성된 제목 id를 aria-labelledby로 참조합니다. 제목이 없으면 깨진 참조를 만들지 않도록 aria-labelledby도 생략됩니다.

children

본문 콘텐츠

title?

헤더 제목

subtitle?

제목 아래 보조 텍스트

actions?

헤더 우측 액션 요소

footer?

하단 푸터 콘텐츠

className?

추가 Tailwind 클래스

id?

카드 식별자. title과 함께 사용하면 제목 기반 aria-labelledby를 연결

headerClassName?

헤더 영역에 추가할 클래스

bodyClassName?

본문 영역에 추가할 클래스

footerClassName?

푸터 영역에 추가할 클래스

EXAMPLE 1

기본 Card

콘텐츠를 한 덩어리로 묶는 가장 기본적인 카드 구조입니다.

프로젝트 요약

이번 스프린트 핵심 지표

운영 정상12개 작업 완료리뷰 2건 대기
기본 Card: title + subtitle + 본문 조합
jsx
<Lib.Card title="프로젝트 요약" subtitle="이번 스프린트 핵심 지표">
  <div className="flex flex-wrap gap-2 text-sm">
    <Lib.Badge variant="success" pill>운영 정상</Lib.Badge>
    <Lib.Badge variant="primary" pill>12개 작업 완료</Lib.Badge>
    <Lib.Badge variant="neutral" pill>리뷰 2건 대기</Lib.Badge>
  </div>
</Lib.Card>
EXAMPLE 2

액션/푸터

헤더 액션과 푸터 메타 정보를 함께 배치한 운영 화면형 카드입니다.

배포 체크리스트

릴리즈 전 필수 확인

완료
12건
진행 중
3건
마지막 업데이트: 방금 전
actions + footer 사용
jsx
<Lib.Card
  title="배포 체크리스트"
  subtitle="릴리즈 전 필수 확인"
  actions={<Lib.Button size="sm" onClick={() => showAlert('체크리스트 액션')}>검토 시작</Lib.Button>}
  footer={<span>마지막 업데이트: 방금 전</span>}
>
  <div className="grid gap-3 sm:grid-cols-2">
    <div className="rounded-lg bg-slate-50 px-3 py-2 ring-1 ring-slate-200/80">
      <div className="text-xs font-semibold uppercase tracking-wide text-slate-500">완료</div>
      <div className="mt-1 text-lg font-semibold text-slate-950">12건</div>
    </div>
    <div className="rounded-lg bg-indigo-50 px-3 py-2 ring-1 ring-indigo-100">
      <div className="text-xs font-semibold uppercase tracking-wide text-indigo-600">진행 중</div>
      <div className="mt-1 text-lg font-semibold text-indigo-700">3건</div>
    </div>
  </div>
</Lib.Card>
EXAMPLE 3

본문 전용

헤더 없이 본문만 강조할 때 사용하는 간결한 정보 패널입니다.

System note
본문만으로도 강조되는 패널

간단한 안내, 공지, 상태 메모를 헤더 없이 표시할 때 사용합니다.

본문 전용 Card: className/bodyClassName으로 강조 패널 구성
jsx
<Lib.Card className="bg-slate-950 text-white ring-slate-800" bodyClassName="p-5 text-slate-200">
  <div className="text-xs font-semibold uppercase tracking-wide text-slate-400">System note</div>
  <div className="mt-2 text-base font-semibold text-white">본문만으로도 강조되는 패널</div>
  <p className="mt-1 text-sm text-slate-300">간단한 안내, 공지, 상태 메모를 헤더 없이 표시할 때 사용합니다.</p>
</Lib.Card>
EXAMPLE 4

조합 예시

Badge, Icon, footer를 조합해 실제 대시보드 카드에 가까운 구조를 보여줍니다.

고객 세그먼트

활성 사용자 그룹

New
프리미엄 전환 후보
최근 30일 활동량이 높은 계정 128개
업데이트: 방금 전
Badge, Icon 조합
jsx
<Lib.Card
  title="고객 세그먼트"
  subtitle="활성 사용자 그룹"
  actions={<Lib.Badge variant="primary" pill>New</Lib.Badge>}
  footer={<div className="flex items-center gap-2 text-xs text-slate-500"><Lib.Icon icon="md:MdSchedule" /> 업데이트: 방금 전</div>}
>
  <div className="flex items-start gap-3">
    <div className="flex h-12 w-12 items-center justify-center rounded-xl bg-indigo-50 text-indigo-700 ring-1 ring-inset ring-indigo-100">
      <Lib.Icon icon="ri:RiUserSmileLine" size="22px" />
    </div>
    <div>
      <div className="font-semibold text-slate-900">프리미엄 전환 후보</div>
      <div className="text-sm text-slate-500">최근 30일 활동량이 높은 계정 128개</div>
    </div>
  </div>
</Lib.Card>

26. 테이블 (Table)

설명

데이터 테이블과 카드 목록을 같은 사용 방식으로 렌더링합니다. 외부 상태 제어 또는 자체 페이지 이동, 주소 검색 조건, 브라우저 저장 값 유지를 지원해 실제 관리 화면의 목록 경험을 빠르게 구성할 수 있습니다.

데이터
data/dataListcolumnsrowKey?
페이지
page?pageSize?defaultPage?onPageChange?pageParam?persistKey?
표현
variant?renderCard?gridClassName?empty?loading?status?
스타일
className?headerClassName?rowClassName?cellClassName?rowsClassName?
EXAMPLE 1

기본 테이블

주소의 검색 조건과 세션 저장 값을 함께 사용하는 기본 데이터 테이블입니다.

ID
이름
이메일
권한
1
사용자 1
user1@example.com
Admin
2
사용자 2
user2@example.com
Editor
3
사용자 3
user3@example.com
Viewer
4
사용자 4
user4@example.com
Admin
5
사용자 5
user5@example.com
Editor
6
사용자 6
user6@example.com
Viewer
7
사용자 7
user7@example.com
Admin
8
사용자 8
user8@example.com
Editor
9
사용자 9
user9@example.com
Viewer
10
사용자 10
user10@example.com
Admin
기본 테이블: URL(page) 동기화 + 세션 보존, 권한 Badge 표시
jsx
<Lib.EasyTable
  data={tableRowList}
  columns={tableColumnList}
  pageParam="page"
  persistKey="table-basic"
  defaultPage={1}
  pageSize={10}
  className="shadow-sm"
/>
EXAMPLE 2

외부 상태 제어

page/onPageChange를 외부 상태로 관리하는 제어형 페이지네이션 예시입니다.

ID
이름
이메일
권한
6
사용자 6
user6@example.com
Viewer
7
사용자 7
user7@example.com
Admin
8
사용자 8
user8@example.com
Editor
9
사용자 9
user9@example.com
Viewer
10
사용자 10
user10@example.com
Admin
제어형 페이지: page/onPageChange로 바깥에서 관리 (pageSize=5)
jsx
const [pageNo, setPageNo] = useState(2);

<Lib.EasyTable
  data={tableRowList}
  columns={tableColumnList}
  page={pageNo}
  pageSize={5}
  maxPageButtons={7}
  onPageChange={setPageNo}
/>
EXAMPLE 3

카드 변형

같은 데이터 소스를 카드 그리드로 보여주는 사용자 목록 패턴입니다.

#1
사용자 1
Admin
user1@example.com
#2
사용자 2
Editor
user2@example.com
#3
사용자 3
Viewer
user3@example.com
#4
사용자 4
Admin
user4@example.com
#5
사용자 5
Editor
user5@example.com
#6
사용자 6
Viewer
user6@example.com
#7
사용자 7
Admin
user7@example.com
#8
사용자 8
Editor
user8@example.com
카드 변형: variant="card" + renderCard로 카드 UI 구성
jsx
<Lib.EasyTable
  variant="card"
  data={tableRowList}
  pageSize={8}
  renderCard={(row) => (
    <div className="rounded-xl bg-white p-4 shadow-sm ring-1 ring-slate-200/80 transition-shadow hover:-translate-y-0.5 hover:shadow-md">...</div>
  )}
/>
EXAMPLE 4

커스텀 스타일

행과 셀을 분리된 카드처럼 표현한 정돈된 업무 화면 스타일입니다.

ID
이름
이메일
권한
1
사용자 1
user1@example.com
Admin
2
사용자 2
user2@example.com
Editor
3
사용자 3
user3@example.com
Viewer
4
사용자 4
user4@example.com
Admin
5
사용자 5
user5@example.com
Editor
6
사용자 6
user6@example.com
Viewer
사용자 정의 스타일: 셀에 rounded-lg와 ring/shadow를 적용하고 헤더·행 간격을 분리한 구성
jsx
<Lib.EasyTable
  data={tableRowList}
  columns={tableStyleColList}
  headerClassName="bg-transparent gap-2"
  rowClassName="gap-2 !bg-transparent !border-0 hover:!bg-transparent"
  rowsClassName="mt-2 space-y-2"
  cellClassName="rounded-lg bg-white p-3 shadow-sm ring-1 ring-slate-200/80"
  pageSize={6}
/>
EXAMPLE 5

빈 상태

데이터가 없을 때 사용자에게 명확한 안내를 제공하는 상태 예시입니다.

ID
이름
이메일
권한
표시할 데이터가 없습니다.
빈 상태/메시지 커스터마이즈
jsx
<Lib.EasyTable data={[]} columns={tableColumnList} empty="표시할 데이터가 없습니다." />

27. 페이지네이션 (Pagination)

설명

독립 컴포넌트로 제어형 페이지 이동을 제공하며, Table 내장 페이징과 같은 상호작용 계약을 공유합니다. 목록 하단의 방향 버튼, edge 이동, 번호 윈도우를 일관된 컨트롤로 제공합니다.

page

현재 페이지 번호 (1부터)

pageCount

전체 페이지 수

onChange

페이지 변경 시 새 페이지 전달

maxButtons?

표시할 최대 번호 버튼

showEdges?

처음/끝 버튼과 생략 표시 여부

className?

래퍼 추가 클래스

EXAMPLE 1

기본 제어형 페이지네이션

목록 하단에 바로 넣기 좋은 기본 page/onChange 패턴입니다.

사용자 목록
총 120건 중 현재 페이지를 제어합니다.
Page 2 / 12
기본 제어형 페이지네이션: page/onChange + 현재 페이지 상태 표시
jsx
const [pageNo, setPageNo] = useState(2);

<Lib.Pagination
  page={pageNo}
  pageCount={12}
  onChange={setPageNo}
  className="rounded-full bg-slate-50 px-2 py-1 ring-1 ring-slate-200/80"
/>
EXAMPLE 2

대용량/버튼 제한

페이지 수가 많을 때 번호 버튼을 제한하고 edge 이동을 유지하는 패턴입니다.

대용량 로그
번호 버튼을 5개로 제한하고 처음/끝 이동을 유지합니다.
Page 5 / 50
버튼 수 제한(maxButtons=5) 대용량 페이지 + edge 이동 유지
jsx
const [pageNo, setPageNo] = useState(5);

<Lib.Pagination
  page={pageNo}
  pageCount={50}
  maxButtons={5}
  onChange={setPageNo}
  className="rounded-full bg-white px-2 py-1 shadow-sm"
/>

28. 탭 (Tab)

설명

Tab 컴포넌트는 Tab.Item을 사용해 관련 콘텐츠 패널을 묶습니다. 기본은 분할 버튼 형태이며, 밀도 높은 화면에서는 variant="underline"으로 전환해 같은 사용 방식 안에서 두 가지 탭 스타일을 유지합니다.

dataObj?/dataKey?

현재 탭 인덱스와 데이터 필드를 연결

tabIndex?

초기 또는 제어 탭 인덱스

onChange?

탭 변경 시 호출

variant?

segmented 또는 underline

className?

래퍼 추가 클래스

children

Tab.Item 목록

EXAMPLE 1

기본 사용법

EasyObj 데이터 연결로 현재 탭을 관리하는 기본 분할형 탭입니다.

전체 업무
24
완료
18
검토 중
6
EasyObj를 사용한 기본 분할형 탭
jsx
const tabDataObj = Lib.EasyObj({
    selectedTab: 0
});

<Lib.Tab dataObj={tabDataObj} dataKey="selectedTab">...</Lib.Tab>
EXAMPLE 2

제어 컴포넌트

tabIndex/onChange를 외부 상태에 연결해 화면 상태를 직접 제어합니다.

activeTab: 0

사용자 프로필

tabIndex와 onChange를 직접 연결한 제어 탭 예시입니다.

tabIndex와 onChange를 외부 상태에 연결한 제어 예시
jsx
const [activeTab, setActiveTab] = useState(0);

<Lib.Tab tabIndex={activeTab} onChange={setActiveTab}>...</Lib.Tab>
EXAMPLE 3

스타일링

className으로 주변 배경과 밀도를 조정한 관리 화면형 탭입니다.

서비스 정상응답 132ms업데이트 09:16
className으로 주변 배경을 조정한 사용자 정의 스타일
jsx
<Lib.Tab
    className="rounded-xl bg-white p-4 shadow-sm ring-1 ring-slate-200/80"
    dataObj={tabDataObj}
    dataKey="customTab"
>...</Lib.Tab>
EXAMPLE 4

밑줄 스타일

variant="underline"을 prop으로 유지해 밀도 높은 화면의 상단 탭에 사용합니다.

밑줄형 탭은 밀도 높은 화면에서 콘텐츠 패널을 과하게 감싸지 않고 사용할 수 있습니다.
variant="underline" 밑줄 스타일을 prop으로 유지
jsx
<Lib.Tab variant="underline" dataObj={tabDataObj} dataKey="underlineTab">...</Lib.Tab>
EXAMPLE 5

아이콘 탭

Tab.Item title에 JSX를 전달해 아이콘과 텍스트를 함께 표시합니다.

탭 제목에 아이콘과 텍스트를 함께 사용할 수 있습니다.
아이콘이 있는 탭
jsx
<Lib.Tab dataObj={tabDataObj} dataKey="iconTab">...</Lib.Tab>

29. 드로어 (Drawer)

설명

화면 측면에서 슬라이드 인 되는 패널입니다. 외부 Collapse 탭과 리사이즈를 지원하며 Tailwind px 클래스 기반 크기 설정이 가능합니다.

  • isOpen: 열림 상태
  • onClose?: 닫힘 콜백
  • side?: 위치 'right' | 'left' | 'top' | 'bottom'
  • size?: 패널 크기 Tailwind 클래스 문자열(min-[1468px]:w-[360px], min-[1468px]:h-[220px] 등)
  • closeOnBackdrop?: 배경 클릭 시 닫힘
  • closeOnEsc?: ESC 키로 닫힘
  • resizable?: 드래그로 크기 조절
  • collapseButton?: 접기 버튼 표시
  • className?: 추가 Tailwind 클래스
  • children?: 패널 내용

오른쪽 (기본)

오른쪽에서 열리는 기본 드로어 (리사이즈 가능, 핸들 포함)
jsx
<Lib.Drawer isOpen={open} onClose={close} side="right" resizable collapseButton>패널 내용</Lib.Drawer>

오른쪽 (size="min-[1468px]:w-[360px]")

오른쪽 드로어 너비를 Tailwind px 클래스 문자열로 지정(size="min-[1468px]:w-[360px]")
jsx
<Lib.Drawer isOpen={open} onClose={close} side="right" size="min-[1468px]:w-[360px]" collapseButton>width 360px</Lib.Drawer>

왼쪽 (size="min-[1468px]:w-[420px]")

왼쪽 드로어 너비를 Tailwind px 클래스 문자열로 지정(size="min-[1468px]:w-[420px]")
jsx
<Lib.Drawer isOpen={open} onClose={close} side="left" size="min-[1468px]:w-[420px]" collapseButton>width 420px</Lib.Drawer>

위쪽 (size="min-[1468px]:h-[220px]")

위쪽 드로어 높이를 Tailwind px 클래스 문자열로 지정(size="min-[1468px]:h-[220px]")
jsx
<Lib.Drawer isOpen={open} onClose={close} side="top" size="min-[1468px]:h-[220px]" collapseButton>height 220px</Lib.Drawer>

아래쪽 (size="min-[1468px]:h-[260px]")

아래쪽 드로어 높이를 Tailwind px 클래스 문자열로 지정(size="min-[1468px]:h-[260px]")
jsx
<Lib.Drawer isOpen={open} onClose={close} side="bottom" size="min-[1468px]:h-[260px]" collapseButton>height 260px</Lib.Drawer>

카드 샘플

카드 컴포넌트를 포함한 드로어
jsx
<Lib.Drawer isOpen={open} onClose={close} side="right" collapseButton><Lib.Card title="카드 샘플">드로어 안 카드</Lib.Card></Lib.Drawer>

메뉴 샘플

리스트 메뉴를 담은 드로어
jsx
<Lib.Drawer isOpen={open} onClose={close} side="left" collapseButton><ul className="p-4 space-y-2"><li>...</li></ul></Lib.Drawer>

30. 모달 (Modal)

설명

Modal 컴포넌트는 Header, Body, Footer 영역을 가진 팝업 대화상자입니다.

5가지 크기(sm, md, lg, xl, full)를 지원하며, full은 화면 가장자리 16px 여백을 둔 너비·높이 전체 영역을 사용합니다.

ESC 키, 배경 클릭, 포커스 이동 제한, 기본 접근성 이름, 선택적 드래그 이동을 지원합니다.

  • isOpen: 열림 상태
  • onClose?: 닫힘 콜백
  • size?: 'sm' | 'md' | 'lg' | 'xl' | 'full'
  • draggable?: 헤더 드래그 이동
  • closeOnBackdrop?: 배경 클릭 시 닫힘
  • closeOnEsc?: ESC 키로 닫힘
  • top?/left?: 초기 위치 지정
  • className?: 추가 Tailwind 클래스
  • children: 모달 내부 콘텐츠

31. 리치 에디터 (EasyEditor)

설명

EasyEditor는 Tiptap 기반 리치 텍스트 에디터로, EasyObj 데이터 연결과 미리 구성된 확장 기능을 통해 쉽게 사용할 수 있습니다. 기본 직렬화는 JSON이며 serialization="html" | "text"로 모드를 바꿀 수 있습니다. 글자 크기, 색상, 정렬, 링크, 이미지/파일 첨부, Editor/HTML 모드 전환 등 핵심 기능을 제공합니다.

  • dataObj + dataKey: EasyObj 객체와 연결합니다. JSON을 기본 직렬화 형식으로 사용합니다.
  • value + onChange: 외부 상태로 값을 제어합니다.
  • serialization?: 'json' | 'html' | 'text' (기본: 'json')
  • extensions?: Tiptap Extension 배열 (메모이즈되어 불필요한 재생성 방지)
  • imageUploadUrl?, fileUploadUrl?: 업로드 엔드포인트 (기본 제공 Alert 안내)
  • onUploadImage?, onUploadFile?: 커스텀 업로드 함수 주입 가능
  • toolbar?: 툴바 표시 여부 (기본: true)
  • status?: 'idle' | 'loading' | 'error' | 'success', 상태에 따른 스타일
  • readOnly?: 읽기 전용 모드 (HTML 모드 전환 시 비활성화)
  • Editor/HTML 모드 전환 시 HTML을 즉시 반영하며, 연결된 데이터에도 동기화됩니다.

툴바에서 폰트, 색상, 정렬, HTML 모드를 시험해보세요.

현재 값 요약: 내용 없음

EasyObj 데이터 연결 기반 기본 사용

jsx
<Lib.EasyEditor
  dataObj={editorDataObj}
  dataKey="announcement"
  serialization="html"
  placeholder="팀 공지를 작성하세요"
  label="공지 작성"
  helperText="툴바에서 폰트, 색상, 정렬, HTML 모드를 시험해보세요."
/>

status='success'로 상태 프리셋을 표시합니다.

현재 값 요약: 온보딩 가이드 새로운 팀원을 환영합니다. 아래 체크리스트를 확인하세요.

초기 콘텐츠가 있는 데이터 연결 예시

jsx
<Lib.EasyEditor
  dataObj={editorDataObj}
  dataKey="onboardingGuide"
  serialization="html"
  placeholder="온보딩 가이드를 작성하세요"
  label="가이드 편집"
  status="success"
  helperText="status='success'로 상태 프리셋을 표시합니다."
/>
<h3>HTML 메모</h3><p>외부 상태 제어에서는 <strong>serialization="html"</strong>을 사용합니다.</p>

EasyObj 데이터 연결 + HTML 직렬화

jsx
const editorDataObj = Lib.EasyObj({ htmlMemo: '<p>초기 HTML</p>' });

<Lib.EasyEditor
  dataObj={editorDataObj}
  dataKey="htmlMemo"
  serialization="html"
  placeholder="HTML 문자열을 직접 관리"
  label="HTML 편집기"
/>

툴바 숨김 + 수정 불가

오류 스타일 및 안내

처리 중 상태

성공 스타일

readOnly/invalid/status 매트릭스 예시

jsx
<div className="grid md:grid-cols-2 gap-4">
  <Lib.EasyEditor value={'<p>읽기 전용 내용</p>'} serialization="html" readOnly toolbar={false} />
  <Lib.EasyEditor value={'<p>유효성 오류 예시</p>'} serialization="html" invalid />
  <Lib.EasyEditor value={'<p>로딩 상태</p>'} serialization="html" status="loading" />
  <Lib.EasyEditor value={'<p>성공 상태</p>'} serialization="html" status="success" />
</div>

32. 차트 (EasyChart)

설명

Recharts를 기반으로 EasyList와 배열 데이터를 지원하는 카드형 차트 컴포넌트입니다.

EasyList 또는 배열 데이터를 그대로 받아 카드 스타일로 차트를 렌더링합니다.

시리즈는 {seriesId, seriesNm, dataKey, type, color} 구조를 권장합니다.

Prop설명
dataListEasyList/배열 차트 데이터
seriesListEasyList/배열 시리즈 ({seriesId, seriesNm, dataKey, type, color})
xKeyX축에 사용할 필드 키 (기본 label)
type기본 시리즈 타입 line|bar|area|pie|donut (기본 line)
loading / status로딩/에러/빈 상태 표시 플래그
empty빈 상태 메시지 혹은 노드
actions카드 우측 액션 영역
hideLegend범례 숨김 여부
legendFontSize범례 글자 크기(px, 기본 12)
showPieLabels파이/도넛 외부 라벨 표시 여부(도넛 기본 false, 좁은 파이 자동 숨김)
yAxisWidthY축 라벨 영역 너비(px, 최소 44, 기본 52)

Example 1

기본 라인 차트 예시

월별 가입 추이

가입자와 활성 이용자 비교

jsx
const sampleData = [
  { label: "1월", signups: 120, active: 90, churn: 12 },
  { label: "2월", signups: 150, active: 110, churn: 15 },
  { label: "3월", signups: 180, active: 130, churn: 18 },
  { label: "4월", signups: 220, active: 170, churn: 16 },
  { label: "5월", signups: 240, active: 190, churn: 20 },
];

<EasyChart
  title="월별 가입 추이"
  subtitle="가입자와 활성 이용자 비교"
  dataList={sampleDataList}
  seriesList={[
    { seriesId: "signups", seriesNm: "가입자", dataKey: "signups", color: "#4f46e5" },
    { seriesId: "active", seriesNm: "활성이용자", dataKey: "active", color: "#10b981" },
  ]}
  xKey="label"
  type="line"
  hideLegend={false}
  height={260}
  actions={<Button size="sm">내보내기</Button>}
/>

Example 2

단일 바 차트

월별 유입 비교

가입자/활성 이용자 막대 비교

jsx
const sampleData = [
  { label: "1월", signups: 120, active: 90, churn: 12 },
  { label: "2월", signups: 150, active: 110, churn: 15 },
  { label: "3월", signups: 180, active: 130, churn: 18 },
  { label: "4월", signups: 220, active: 170, churn: 16 },
  { label: "5월", signups: 240, active: 190, churn: 20 },
];

<EasyChart
  title="월별 유입 비교"
  subtitle="가입자/활성 이용자 막대 비교"
  dataList={sampleDataList}
  seriesList={[
    { seriesId: "signups", seriesNm: "가입자", dataKey: "signups", type: "bar", color: "#4f46e5" },
    { seriesId: "active", seriesNm: "활성이용자", dataKey: "active", type: "bar", color: "#10b981" },
  ]}
  xKey="label"
  type="bar"
  hideLegend
  height={260}
/>

Example 3

바+라인 혼합 스택 차트

획득/이탈 믹스

스택 막대와 이탈 라인 동시 확인

jsx
const sampleData = [
  { label: "1월", signups: 120, active: 90, churn: 12 },
  { label: "2월", signups: 150, active: 110, churn: 15 },
  { label: "3월", signups: 180, active: 130, churn: 18 },
  { label: "4월", signups: 220, active: 170, churn: 16 },
  { label: "5월", signups: 240, active: 190, churn: 20 },
];

<EasyChart
  title="획득/이탈 믹스"
  subtitle="스택 막대와 이탈 라인 동시 확인"
  dataList={sampleDataList}
  seriesList={[
    { seriesId: "signups", seriesNm: "가입자", dataKey: "signups", type: "bar", color: "#4f46e5", stackId: "v" },
    { seriesId: "active", seriesNm: "활성이용자", dataKey: "active", type: "bar", color: "#10b981", stackId: "v" },
    { seriesId: "churn", seriesNm: "이탈", dataKey: "churn", type: "line", color: "#f43f5e" },
  ]}
  xKey="label"
  type="bar"
  hideLegend={false}
  xLabelFormatter={(label) => `${label} /22`}
  yLabelFormatter={(val) => `${val}명`}
  height={260}
/>

Example 4

파이 차트

가입 구성 비율

월별 데이터의 구성 분포

jsx
const sampleData = [
  { label: "1월", signups: 120, active: 90, churn: 12 },
  { label: "2월", signups: 150, active: 110, churn: 15 },
  { label: "3월", signups: 180, active: 130, churn: 18 },
  { label: "4월", signups: 220, active: 170, churn: 16 },
  { label: "5월", signups: 240, active: 190, churn: 20 },
];

<EasyChart
  title="가입 구성 비율"
  subtitle="월별 데이터의 구성 분포"
  dataList={sampleDataList}
  seriesList={[
    { seriesId: "signups", seriesNm: "가입자", dataKey: "signups", type: "pie", color: "#4f46e5" },
    { seriesId: "active", seriesNm: "활성이용자", dataKey: "active", type: "pie", color: "#10b981" },
    { seriesId: "churn", seriesNm: "이탈", dataKey: "churn", type: "pie", color: "#f43f5e" },
  ]}
  xKey="label"
  type="pie"
  hideLegend={false}
  height={260}
/>

Example 5

도넛 차트

활동 비중 도넛

주요 지표의 상대 비중

jsx
const sampleData = [
  { label: "1월", signups: 120, active: 90, churn: 12 },
  { label: "2월", signups: 150, active: 110, churn: 15 },
  { label: "3월", signups: 180, active: 130, churn: 18 },
  { label: "4월", signups: 220, active: 170, churn: 16 },
  { label: "5월", signups: 240, active: 190, churn: 20 },
];

<EasyChart
  title="활동 비중 도넛"
  subtitle="주요 지표의 상대 비중"
  dataList={sampleDataList}
  seriesList={[
    { seriesId: "signups", seriesNm: "가입자", dataKey: "signups", type: "donut", color: "#4f46e5" },
    { seriesId: "active", seriesNm: "활성이용자", dataKey: "active", type: "donut", color: "#10b981" },
    { seriesId: "churn", seriesNm: "이탈", dataKey: "churn", type: "donut", color: "#f43f5e" },
  ]}
  xKey="label"
  type="donut"
  hideLegend
  height={260}
/>

Example 6

로딩 상태

차트 로딩

jsx
<EasyChart title="차트 로딩" dataList={[]} seriesList={[]} xKey="label" loading hideLegend />

Example 7

빈 상태

빈 차트

데이터 없음

jsx
<EasyChart title="빈 차트" dataList={[]} seriesList={[]} xKey="label" status="empty" empty="데이터 없음" />

Example 8

에러 상태 + 에러 메시지 표시

차트 오류

jsx
const sampleData = [
  { label: "1월", signups: 120, active: 90, churn: 12 },
  { label: "2월", signups: 150, active: 110, churn: 15 },
  { label: "3월", signups: 180, active: 130, churn: 18 },
  { label: "4월", signups: 220, active: 170, churn: 16 },
  { label: "5월", signups: 240, active: 190, churn: 20 },
];

<EasyChart title="차트 오류" dataList={sampleDataList} seriesList={[]} xKey="label" status="error" errorText="API 에러가 발생했습니다." />

33. PDF 뷰어 (PdfViewer)

설명

로컬 파일 또는 외부 URL의 PDF를 미리봅니다. public/pdf-sample.pdf 예제가 포함되어 있습니다.

  • Props: src(string|File|Blob|ArrayBuffer), workerSrc?, withToolbar?
  • 외부 URL은 CORS 허용이 필요합니다.

Example 1

public 폴더의 pdf-sample.pdf 미리보기

public/pdf-sample.pdf 파일이 제공되면 아래 뷰어가 렌더링됩니다.

PDF preview

Public path

PDF 소스를 확인할 수 없습니다.
PDF 소스를 확인할 수 없습니다.
jsx
<Lib.PdfViewer src="/pdf-sample.pdf" />

Example 2

withToolbar=false 예시

툴바 비활성화(페이지/검색/줌 UI 숨김)

PDF preview

Public path

PDF 소스를 확인할 수 없습니다.
PDF 소스를 확인할 수 없습니다.
jsx
<Lib.PdfViewer src="/pdf-sample.pdf" withToolbar={false} />

Example 3

로컬 파일 선택 후 뷰어로 표시

jsx
const [localFile, setLocalFile] = useState(null);

<input
  type="file"
  accept="application/pdf"
  onChange={(event) => setLocalFile(event.target.files?.[0] ?? null)}
/>
{localFile && <Lib.PdfViewer src={localFile} />}

Example 4

원격 URL로 PDF 표시(서버 CORS 허용 필요)

jsx
const [remoteUrl, setRemoteUrl] = useState('');

<input
  value={remoteUrl}
  onChange={(event) => setRemoteUrl(event.target.value)}
/>
{remoteUrl && <Lib.PdfViewer src={remoteUrl} />}

Example 5

404/네트워크 오류시 오류 안내 렌더링

오류 상태(404) 시 Empty 안내로 대체

PDF preview

Public path

PDF 소스를 확인할 수 없습니다.
PDF 소스를 확인할 수 없습니다.
jsx
<Lib.PdfViewer src="/not-exists.pdf" />