Toast
개요
Toast는 사용자 액션의 결과를 일시적으로 표시하는 알림 컴포넌트입니다. Cals에서는 예약 성공, 취소, 상태 변경 등 즉각적인 피드백을 제공하는 데 사용됩니다.
언제 사용하는가
- 예약 생성/수정/삭제 성공 알림
- 예약 상태 변경 완료 알림
- 파일 업로드 완료 알림
- 설정 저장 완료 알림
- 오류 발생 시 즉각적인 피드백
언제 사용하지 말아야 하는가
- 중요한 정보 전달 → Alert 사용
- 사용자 확인 필요 → Dialog 사용
- 영구적인 상태 표시 → Badge 또는 Alert 사용
- 복잡한 정보 → Popover 또는 Dialog 사용
설치
npx @vortex/cli add toast기본 사용법
import { useToast } from "@/hooks/use-toast";
import { Button } from "@/components/ui/button";
export default function ToastDemo() {
const { toast } = useToast();
return (
<Button
onClick={() => {
toast({
title: "예약 완료",
description: "2024년 1월 15일 14:00 예약이 완료되었습니다.",
});
}}
>
예약하기
</Button>
);
}Variants
Default
일반적인 정보 메시지를 표시합니다.
toast({
title: "예약 확정",
description: "예약이 확정되었습니다.",
});Success
성공 메시지를 표시합니다.
toast({
title: "예약 성공",
description: "2024년 1월 15일 14:00 예약이 완료되었습니다.",
variant: "success",
});Destructive (Error)
오류 메시지를 표시합니다.
toast({
title: "예약 실패",
description: "선택하신 시간대가 이미 예약되었습니다.",
variant: "destructive",
});With Action
액션 버튼을 포함한 Toast를 표시합니다.
toast({
title: "예약 취소",
description: "예약이 취소되었습니다.",
action: (
<Button variant="outline" size="sm">
실행 취소
</Button>
),
});Cals 브랜딩
브랜드 컬러
Cals의 Primary Pink를 활용한 브랜드 Toast 스타일입니다.
// components/ui/toast.tsx에 커스텀 variant 추가
const toastVariants = cva("...", {
variants: {
variant: {
default: "...",
destructive: "...",
cals: "border-cals-primary bg-cals-primary text-white",
},
},
});toast({
title: "Cals 예약",
description: "새로운 예약이 생성되었습니다.",
variant: "cals",
});예약 상태 컬러
예약 상태별 Toast 스타일을 제공합니다.
// Available - 예약 가능
toast({
title: "예약 가능",
description: "해당 시간대에 예약하실 수 있습니다.",
className: "border-green-500 bg-green-50 text-green-900",
});
// Pending - 승인 대기
toast({
title: "승인 대기",
description: "예약 요청이 접수되었습니다.",
className: "border-orange-500 bg-orange-50 text-orange-900",
});
// Confirmed - 예약 확정
toast({
title: "예약 확정",
description: "2024년 1월 15일 14:00 예약이 확정되었습니다.",
className: "border-blue-500 bg-blue-50 text-blue-900",
});
// Cancelled - 예약 취소
toast({
title: "예약 취소",
description: "예약이 취소되었습니다.",
className: "border-red-500 bg-red-50 text-red-900",
});
// Completed - 예약 완료
toast({
title: "서비스 완료",
description: "예약하신 서비스가 완료되었습니다.",
className: "border-purple-500 bg-purple-50 text-purple-900",
});브랜드 비교표
| 속성 | Foundation | iCignal | Cals |
|---|---|---|---|
| Primary Color | Neutral Gray | Corporate Blue #0066cc | Primary Pink #e91e63 |
| Use Case | 범용 알림 | 기업 액션 피드백 | 예약 액션 결과 |
| Duration | 3-5초 | 5초 (중요도 높음) | 3초 (빠른 피드백) |
| Position | Bottom Right | Top Right | Bottom Right |
| Action Button | Optional | Required (추적) | Optional (실행 취소) |
| Status Colors | Semantic | Corporate Blue 기반 | 5가지 예약 상태 컬러 |
Props API
toast()
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | - | Toast 제목 |
| description | string | - | Toast 설명 |
| variant | "default" | "destructive" | "default" | Toast 스타일 변형 |
| duration | number | 3000 | 표시 시간 (ms) |
| action | ReactNode | - | 액션 버튼 |
| className | string | - | 커스텀 CSS 클래스 |
useToast()
| Return | Type | Description |
|---|---|---|
| toast | (options: ToastOptions) => void | Toast 표시 함수 |
| dismiss | (id?: string) => void | Toast 닫기 함수 |
| toasts | Toast[] | 현재 표시 중인 Toast 목록 |
접근성
- Role:
role="status"또는role="alert"자동 적용 - ARIA:
aria-live="polite"(일반) 또는aria-live="assertive"(오류) 사용 - Focus Management: Toast는 포커스를 가져가지 않음
- Keyboard: 액션 버튼은 Tab으로 접근 가능
- Screen Reader: 제목과 설명을 자동으로 읽음
- Dismiss: ESC 키로 닫기 가능
예제
예약 상태별 Toast
import { useToast } from "@/hooks/use-toast";
import { Button } from "@/components/ui/button";
export default function ReservationToasts() {
const { toast } = useToast();
const handleAvailable = () => {
toast({
title: "예약 가능",
description: "해당 시간대에 예약하실 수 있습니다.",
className: "border-green-500 bg-green-50 text-green-900",
});
};
const handlePending = () => {
toast({
title: "승인 대기",
description:
"예약 요청이 접수되었습니다. 승인까지 최대 24시간 소요됩니다.",
className: "border-orange-500 bg-orange-50 text-orange-900",
duration: 5000,
});
};
const handleConfirmed = () => {
toast({
title: "예약 확정",
description: "2024년 1월 15일 14:00 예약이 확정되었습니다.",
className: "border-blue-500 bg-blue-50 text-blue-900",
});
};
const handleCancelled = () => {
toast({
title: "예약 취소",
description: "예약이 취소되었습니다. 취소 수수료가 부과될 수 있습니다.",
className: "border-red-500 bg-red-50 text-red-900",
action: (
<Button variant="outline" size="sm">
실행 취소
</Button>
),
});
};
const handleCompleted = () => {
toast({
title: "서비스 완료",
description: "예약하신 서비스가 정상적으로 완료되었습니다.",
className: "border-purple-500 bg-purple-50 text-purple-900",
});
};
return (
<div className="space-x-2">
<Button onClick={handleAvailable}>예약 가능</Button>
<Button onClick={handlePending}>승인 대기</Button>
<Button onClick={handleConfirmed}>예약 확정</Button>
<Button onClick={handleCancelled}>예약 취소</Button>
<Button onClick={handleCompleted}>서비스 완료</Button>
</div>
);
}실행 취소 기능
import { useToast } from "@/hooks/use-toast";
import { Button } from "@/components/ui/button";
export default function UndoToast() {
const { toast } = useToast();
const handleCancelReservation = () => {
// 예약 취소 로직
cancelReservation();
// Toast 표시
toast({
title: "예약 취소",
description: "예약이 취소되었습니다.",
className: "border-red-500 bg-red-50 text-red-900",
action: (
<Button
variant="outline"
size="sm"
onClick={() => {
// 실행 취소 로직
undoCancelReservation();
toast({
title: "취소 복구",
description: "예약이 복구되었습니다.",
className: "border-blue-500 bg-blue-50 text-blue-900",
});
}}
>
실행 취소
</Button>
),
duration: 5000, // 실행 취소 시간 확보
});
};
return (
<Button onClick={handleCancelReservation} variant="destructive">
예약 취소
</Button>
);
}
function cancelReservation() {
// 예약 취소 API 호출
}
function undoCancelReservation() {
// 예약 복구 API 호출
}Cals 브랜드 Toast
import { useToast } from "@/hooks/use-toast";
import { Button } from "@/components/ui/button";
export default function CalsBrandToast() {
const { toast } = useToast();
return (
<Button
onClick={() => {
toast({
title: "Cals 예약 시스템",
description: "새로운 예약이 생성되었습니다.",
className: "border-cals-primary bg-cals-primary text-white",
});
}}
>
Cals Toast
</Button>
);
}관련 컴포넌트
Last updated on