Components / Feedback
Toast
일시적인 피드백 메시지를 표시하는 비침습적 알림입니다. 자동 소멸되며, 성공/오류/정보 상태를 지원합니다.
사용법
Toast는 화면 상단 또는 하단에 잠시 나타났다가 자동으로 사라집니다. 기본 3초 후 소멸됩니다.
toast.success('찜 목록에 추가했습니다')
toast.error('네트워크 오류가 발생했습니다')
toast.info('새로운 작품이 등록되었습니다') <div style="position:fixed;bottom:24px;left:50%;transform:translateX(-50%);background:var(--charcoal);color:var(--white);padding:10px 20px;font-size:var(--text-sm);font-weight:500;box-shadow:var(--shadow-lg);z-index:9999"> Toast message here </div>
상태별 스타일
success(초록), error(빨강), info(파랑) 3가지 상태를 제공합니다.
toast.success('메시지') {/* ✓ 초록 아이콘 */}
toast.error('메시지') {/* ✕ 빨간 아이콘 */}
toast.info('메시지') {/* ℹ 파란 아이콘 */} 액션 버튼
Toast에 되돌리기 등 액션 버튼을 추가할 수 있습니다.
toast.success('찜 목록에서 삭제했습니다', {
action: { label: '되돌리기', onClick: () => undo() },
duration: 5000,
}) 접근성
| 속성 | 값 | 설명 |
|---|---|---|
role | "alert" | 중요 알림으로 스크린 리더에 즉시 전달합니다. |
aria-live | "assertive" | 에러 토스트에 적용, polite는 정보 토스트입니다. |
aria-atomic | "true" | 전체 메시지를 한 번에 읽습니다. |
사용 방법 예시
인터페이스
ToastOptions
| 속성 | 필수 | 기본값 | 타입 | 설명 |
|---|---|---|---|---|
message | — | string | 표시할 메시지 텍스트입니다. | |
type | — | success | success | error | info | 토스트 상태입니다. |
duration | — | 3000 | number (ms) | 자동 소멸 시간입니다. |
position | — | top | top | bottom | 표시 위치입니다. |
action | — | — | { label, onClick } | 액션 버튼 정보입니다. |
크기 (Size)
3단계 사이즈 스케일을 지원합니다. 기본값은 md입니다.
Components / Feedback
Modal
사용자의 확인이 필요한 대화 상자입니다. Alert(텍스트) / Action Sheet(옵션 목록) / Bottom Sheet(자유 콘텐츠) 3가지 타입을 지원합니다.
사용법
Modal은 오버레이와 함께 표시되며, 배경 클릭 또는 닫기 버튼으로 닫을 수 있습니다.
작품을 삭제할까요?
삭제된 작품은 복구할 수 없습니다.
<Modal type="alert" open={isOpen} onClose={close}>
<Modal.Title>작품을 삭제할까요?</Modal.Title>
<Modal.Description>삭제된 작품은 복구할 수 없습니다.</Modal.Description>
<Modal.Actions>
<Button variant="weak" onClick={close}>취소</Button>
<Button color="danger" onClick={handleDelete}>삭제</Button>
</Modal.Actions>
</Modal> <!-- Overlay -->
<div style="position:fixed;inset:0;background:var(--alpha-50);z-index:999;display:flex;align-items:center;justify-content:center">
<!-- Modal Card -->
<div style="background:var(--bg-card);width:min(90vw,560px);max-height:90vh;overflow-y:auto;box-shadow:var(--shadow-lg)">
<div style="padding:var(--space-6);border-bottom:1px solid var(--border)">
<h2 style="font-size:var(--text-lg);font-weight:700;color:var(--charcoal);margin:0">Modal Title</h2>
</div>
<div style="padding:var(--space-6)">Content here</div>
<div style="padding:var(--space-4) var(--space-6);border-top:1px solid var(--border);display:flex;justify-content:flex-end;gap:var(--space-3)">
<button class="ch-btn ch-btn--ghost">Cancel</button>
<button class="ch-btn ch-btn--primary">Confirm</button>
</div>
</div>
</div> Alert 타입
화면 중앙에 표시되는 기본 대화 상자입니다. 확인/취소 버튼으로 결정을 유도합니다.
소장 확인
₩ 2,400,000에 소장을 진행합니다.
<Modal type="alert">...</Modal>
{/* 화면 중앙, 최대 너비 280px */} Action Sheet 타입
화면 하단에서 올라오는 옵션 목록입니다. 여러 액션 중 하나를 선택합니다.
<Modal type="actionSheet">
<Modal.Option onClick={share}>공유하기</Modal.Option>
<Modal.Option onClick={report}>신고하기</Modal.Option>
<Modal.Option color="danger" onClick={del}>삭제하기</Modal.Option>
<Modal.Cancel />
</Modal> Bottom Sheet 타입
하단에서 올라오는 자유 콘텐츠 컨테이너입니다. 필터, 폼 등 복잡한 UI에 사용합니다.
필터
<Modal type="bottomSheet" height="auto">
<Modal.Header>필터</Modal.Header>
<Modal.Content>{children}</Modal.Content>
</Modal> 접근성
| 속성 | 값 | 설명 |
|---|---|---|
role | "dialog" | 대화 상자 역할을 명시합니다. |
aria-modal | "true" | 모달 컨텍스트임을 표시합니다. |
aria-labelledby | "{titleId}" | 제목 요소를 참조합니다. |
focus trap | — | 모달 내부에서만 포커스가 이동합니다. |
Escape | — | Escape 키로 모달을 닫습니다. |
사용 방법 예시
삭제할까요?
복구할 수 없습니다.
인터페이스
ModalProps
| 속성 | 필수 | 기본값 | 타입 | 설명 |
|---|---|---|---|---|
type | — | alert | alert | actionSheet | bottomSheet | 모달 타입입니다. |
open | — | boolean | 모달 표시 상태입니다. | |
onClose | — | () => void | 닫기 핸들러입니다. | |
closable | — | true | boolean | 배경 클릭으로 닫기 가능 여부입니다. |
children | — | ReactNode | 모달 내부 콘텐츠입니다. |
크기 (Size)
3단계 사이즈 스케일을 지원합니다. 기본값은 md입니다.
반응형 (Responsive)
브레이크포인트별 동작 변화입니다.
fullscreen, 100vh
Description
centered, max-w: 480px
Description text here
centered, max-w: 560px
Components / Feedback
Notification
CHAART. 전용 알림 리스트 아이템입니다. 거래 알림, 찜 변동, 시스템 공지 등을 유형별로 표시합니다.
사용법
Notification은 아이콘 + 타이틀 + 설명 + 시간 + 읽음 상태로 구성됩니다.
새로운 찜 알림
'빨래터' 작품이 찜 목록에 추가되었습니다.
3분 전
<Notification
type="wishlist"
title="새로운 찜 알림"
description="'빨래터' 작품이 찜 목록에 추가되었습니다."
time="3분 전"
isRead={false}
/> <div style="display:flex;gap:var(--space-3);padding:var(--space-4);border-bottom:1px solid var(--border);background:var(--red-brand-whisper)">
<div style="width:8px;height:8px;background:var(--red-brand);border-radius:50%;margin-top:6px;flex-shrink:0"></div>
<div>
<div style="font-size:var(--text-sm);font-weight:600;color:var(--charcoal)">New notification</div>
<div style="font-size:var(--text-xs);color:var(--text-muted);margin-top:2px">2 minutes ago</div>
</div>
</div> 알림 유형
거래(trade), 찜(wishlist), 시스템(system), 이벤트(event) 4가지 유형을 지원합니다.
거래 완료
소장이 확정되었습니다
찜 알림
찜한 작품 가격이 변동되었습니다
시스템 공지
서비스 업데이트가 예정되어 있습니다
이벤트
신진 작가 할인전이 시작되었습니다
<Notification type="trade" /> {/* ₩ 초록 */}
<Notification type="wishlist" /> {/* ♡ 빨강 */}
<Notification type="system" /> {/* ℹ 파랑 */}
<Notification type="event" /> {/* ★ 주황 */} 읽음/안읽음 상태
안읽음 알림은 배경 하이라이트 + 우측 Red Bean dot으로 구분됩니다.
안읽은 알림
읽은 알림
<Notification isRead={false} /> {/* 배경 하이라이트 + dot */}
<Notification isRead={true} /> {/* 일반 배경 */} 접근성
| 속성 | 값 | 설명 |
|---|---|---|
role | "listitem" | 알림 리스트의 한 항목입니다. |
aria-label | "{title}: {desc}" | 알림의 전체 내용을 전달합니다. |
aria-current | "true" | 안읽음 상태의 알림에 적용됩니다. |
사용 방법 예시
거래 완료
'빨래터' 소장이 확정됨
5분 전
찜 변동
찜한 작품 가격 ↓12%
1시간 전
시스템 업데이트
v2.0 업데이트 안내
어제
인터페이스
NotificationProps
| 속성 | 필수 | 기본값 | 타입 | 설명 |
|---|---|---|---|---|
type | — | trade | wishlist | system | event | 알림 유형입니다. | |
title | — | string | 알림 제목입니다. | |
description | — | — | string | 알림 상세 설명입니다. |
time | — | — | string | 시간 표시 텍스트입니다. |
isRead | — | false | boolean | 읽음 상태입니다. |
onClick | — | — | () => void | 알림 클릭 핸들러입니다. |
크기 (Size)
3단계 사이즈 스케일을 지원합니다. 기본값은 md입니다.
상태 (States)
Notification 아이템의 인터랙션 상태입니다.
새 찜 알림
읽은 알림
새 찜 알림
Components / Feedback
Bottom Sheet
하단에서 올라오는 반투명 시트 컴포넌트입니다. 필터, 옵션 선택, 상세 정보 등을 표시합니다.
사용법
Bottom Sheet는 현재 화면 위에 오버레이 형태로 표시되며, 배경 딤 처리와 함께 하단에서 슬라이드업 됩니다.
작품 필터
<BottomSheet isOpen={true} onClose={handleClose} title="작품 필터">
<FilterChips options={["유화", "수채화", "판화", "조각"]} />
</BottomSheet> <div style="position:fixed;bottom:0;left:0;right:0;background:var(--bg-card);box-shadow:0 -4px 24px rgba(0,0,0,0.1);z-index:999;max-height:80vh;overflow-y:auto">
<div style="width:36px;height:4px;background:var(--alpha-16);border-radius:0;margin:12px auto"></div>
<div style="padding:var(--space-4) var(--space-6)">
<h3 style="font-size:var(--text-base);font-weight:700;margin:0 0 var(--space-4)">Sheet Title</h3>
<p style="font-size:var(--text-sm);color:var(--text-muted)">Content here</p>
</div>
</div> 핸들 바
상단 핸들 바를 드래그하여 시트의 높이를 조절할 수 있습니다. showHandle prop으로 제어합니다.
핸들 있음
시트 콘텐츠
핸들 없음
시트 콘텐츠
<BottomSheet showHandle={true} /> {/* 드래그 가능 */}
<BottomSheet showHandle={false} /> {/* 고정 높이 */} 풀 스크린
fullScreen 모드는 화면 전체를 차지하며, 상단에 닫기 버튼이 표시됩니다. 복잡한 필터나 설정에 적합합니다.
가격대를 선택하세요
<BottomSheet fullScreen title="가격 범위 설정" onClose={handleClose}>
<PriceRangeFilter />
</BottomSheet> 접근성
| 속성 | 값 | 설명 |
|---|---|---|
role | "dialog" | 모달 대화상자임을 명시합니다. |
aria-modal | "true" | 모달 컨텍스트를 선언합니다. |
aria-labelledby | title id | 시트 제목을 참조합니다. |
Escape | 닫기 | Esc 키로 시트를 닫을 수 있습니다. |
사용 방법 예시
배송 옵션
인터페이스
BottomSheetProps
| 속성 | 필수 | 기본값 | 타입 | 설명 |
|---|---|---|---|---|
isOpen | — | boolean | 시트 열림 상태입니다. | |
onClose | — | () => void | 시트 닫기 핸들러입니다. | |
title | — | — | string | 시트 상단 제목입니다. |
showHandle | — | true | boolean | 핸들 바 표시 여부입니다. |
fullScreen | — | false | boolean | 풀 스크린 모드 여부입니다. |
snapPoints | — | [0.5] | number[] | 스냅 포인트 배열 (0~1)입니다. |
children | — | ReactNode | 시트 내부 콘텐츠입니다. |
크기 (Size)
3단계 사이즈 스케일을 지원합니다. 기본값은 md입니다.
상태 (States)
BottomSheet의 인터랙션 상태입니다.
Components / Feedback
Dialog
사용자 확인 또는 입력이 필요한 모달 다이얼로그 컴포넌트입니다. 중요한 작업 전 사용자의 명시적 동의를 구하거나 추가 정보를 입력받을 때 사용합니다.
사용법
<Dialog
open={isOpen}
title="작품을 삭제하시겠습니까?"
description="이 작업은 되돌릴 수 없습니다."
confirmText="삭제"
cancelText="취소"
variant="confirm"
onConfirm={() => handleDelete()}
onCancel={() => setIsOpen(false)}
/> <div style="position:fixed;inset:0;background:var(--alpha-50);display:flex;align-items:center;justify-content:center;z-index:999">
<div style="background:var(--bg-card);padding:var(--space-6);width:min(90vw,400px);text-align:center">
<h3 style="font-size:var(--text-base);font-weight:700;color:var(--charcoal);margin:0 0 8px">Confirm Action?</h3>
<p style="font-size:var(--text-sm);color:var(--text-muted);margin:0 0 24px">This cannot be undone.</p>
<div style="display:flex;gap:var(--space-3);justify-content:center">
<button class="ch-btn ch-btn--ghost">Cancel</button>
<button class="ch-btn ch-btn--primary">Confirm</button>
</div>
</div>
</div> 변형
접근성
| 속성 | 값 | 설명 |
|---|---|---|
role | dialog | 다이얼로그 역할을 스크린 리더에 전달합니다 |
aria-modal | true | 모달 상태를 전달하여 배경 요소 접근을 차단합니다 |
aria-labelledby | 제목 ID | 다이얼로그 제목을 연결합니다 |
aria-describedby | 설명 ID | 다이얼로그 설명을 연결합니다 |
| 키보드 | Escape | ESC 키로 다이얼로그를 닫습니다 |
| 포커스 트랩 | Tab 순환 | 다이얼로그 내부에서만 포커스가 이동합니다 |
사용 방법 예시
인터페이스
DialogProps
| 속성 | 필수 | 기본값 | 타입 | 설명 |
|---|---|---|---|---|
open | — | boolean | 다이얼로그 표시 상태 | |
title | — | string | 다이얼로그 제목 | |
description | — | string | 다이얼로그 설명 텍스트 | |
confirmText | "확인" | string | 확인 버튼 텍스트 | |
cancelText | "취소" | string | 취소 버튼 텍스트 | |
onConfirm | — | () => void | 확인 버튼 클릭 시 콜백 | |
onCancel | — | () => void | 취소 버튼 클릭 시 콜백 | |
variant | "confirm" | "confirm" | "alert" | "prompt" | 다이얼로그 변형 타입 |
크기 (Size)
3단계 사이즈 스케일을 지원합니다. 기본값은 md입니다.
상태 (States)
Dialog의 변형 상태입니다.
Components / Feedback
Loader
콘텐츠 로딩 중임을 시각적으로 알려주는 인디케이터입니다. 스피너, 도트, 프로그레스 바 세 가지 타입을 지원하며 작품 이미지 로딩, 데이터 패칭 등에 활용됩니다.
사용법
기본 로더는 스피너 타입으로 렌더링됩니다. 데이터 요청 중이거나 콘텐츠를 준비할 때 사용합니다.
<Loader /> <Loader type="spinner" label="로딩 중…" />
<div style="width:24px;height:24px;border:2px solid var(--alpha-12);border-top-color:var(--red-brand);border-radius:50%;animation:spin 0.8s linear infinite"></div>
<!-- Add @keyframes spin { to { transform: rotate(360deg) } } --> 타입
세 가지 로더 타입을 제공합니다. 맥락에 맞는 시각 표현을 선택하세요.
<Loader type="spinner" /> <Loader type="dots" /> <Loader type="bar" />
사이즈
로더 크기를 small, medium, large로 조절할 수 있습니다.
<Loader size="small" /> <Loader size="medium" /> <Loader size="large" />
접근성
| 속성 | 값 | 설명 |
|---|---|---|
role | status | 로딩 상태를 나타내는 라이브 영역임을 명시합니다 |
aria-live | "polite" | 상태 변경 시 스크린 리더에 비간섭적으로 알립니다 |
aria-label | "로딩 중" | 로더의 목적을 설명합니다 |
aria-busy | true | 콘텐츠가 아직 준비 중임을 표시합니다 |
사용 방법 예시
인터페이스
LoaderProps
| 속성 | 필수 | 기본값 | 타입 | 설명 |
|---|---|---|---|---|
type | "spinner" | "spinner" | "dots" | "bar" | 로더 시각 유형 | |
size | "medium" | "small" | "medium" | "large" | 로더 크기 | |
color | "brand" | "brand" | "inherit" | string | 인디케이터 색상 | |
label | — | string | 로더 아래 표시할 텍스트 | |
overlay | false | boolean | 오버레이 배경 사용 여부 | |
fullScreen | false | boolean | 전체 화면 로딩 표시 여부 |
크기 (Size)
3단계 사이즈 스케일을 지원합니다. 기본값은 md입니다.
상태 (States)
Loader는 단일 상태(Loading)를 가집니다. 세 가지 타입의 시각 표현을 비교합니다.