Tiro
Tiro Design
Components

Toast

일시적 알림. 상태 변경 결과를 방해 없이 전달.

Mobile

모바일에서 Toast는 화면 가장자리 안전 영역(safe area)을 따라 떠 있는 카드 형태로 표시된다. Web과 시맨틱(자동 dismiss·계층적 priority)은 동일.

  • 위치: 기본은 화면 상단 (notch/status bar 아래) — iOS 관례. 키보드가 떠 있을 땐 키보드 위로 자리. 사용 맥락에 따라 하단도 허용 (예: 화면 상단 Header가 복잡할 때)
  • safe area: useSafeAreaInsets 기반 offset 적용 (top + 12 또는 bottom + 12)
  • 너비: calc(100vw - 32px), max 480px. 좌우 16px 인셋
  • dismiss:
    • 자동 dismiss (info/success 4s, warning/error 6s) — web과 동일
    • Swipe-to-dismiss: 위/아래 또는 좌/우 스와이프로 즉시 닫기 (react-native-toast-message 또는 react-native-reanimated 제스처)
    • 탭 시 dismiss 또는 액션 트리거 (CTA가 있는 toast)
  • hover-to-pause 없음: 모바일은 hover 개념이 없으므로 사용자 인터랙션으로 일시정지 패턴은 long-press로 대체하거나 생략
  • 권장 라이브러리: react-native-toast-message — safe area·queue·animation 내장
  • CTA toast: 우측 액션 버튼은 hit area ≥44pt 확보. CTA가 길어지면 별도 줄로 분리

Preview

preview-mobile

preview-mobile

Top toast — safe area + 12pt offset


구조

ToastProvider
└─ ToastViewport              fixed · bottom-right · w-[360px]
   └─ Toast                   group relative · rounded-xl · border · p-4 · shadow-lg
      ├─ ToastClose            absolute -left-2 -top-2 · h-5 w-5 · rounded-full
      │                        bg-white · ring-1 · shadow-md
      │                        opacity-0 → group-hover:opacity-100
      ├─ div (text, 좌)        flex flex-col gap-0.5
      │  ├─ ToastTitle         label1Medium
      │  └─ ToastDescription   caption1Regular (optional)
      └─ ToastAction           shrink-0 · h-8 · rounded-lg · button2Medium (optional)

Variants

모든 variant는 흰 배경을 공유합니다. 시맨틱 구분은 아이콘 컬러 + 테두리 색상으로만 표현합니다. 제목·설명 텍스트와 액션 버튼은 모든 variant에서 동일합니다.

VariantBorderIconTitleDescriptionAction button
defaultstone-200brown-800stone-400bg-stone-100 text-brown-800
warningamber-200AlertTriangle · amber-500brown-800stone-400bg-amber-100 text-amber-700
destructiverose-200AlertCircle · rose-500brown-800stone-400bg-rose-100 text-rose-700
successlime-200CheckCircle2 · lime-600brown-800stone-400bg-lime-100 text-lime-700

Token Mapping

TokenValue (web)Value (mobile)
position화면 하단 또는 상단 (Radix viewport에 따름)화면 상단 (status bar 아래, safe area + 12pt) — 키보드 시 키보드 위로
widthw-[360px]calc(100vw - 32px), max 480px
backgroundwhite (모든 variant 동일)동일
radiusrounded-xl (16px)동일
shadowshadow-lgnative shadow (iOS) / elevation (Android)
paddingp-4동일
gapgap-3 (icon · text · action 사이)동일
titlelabel1Medium · brown-800동일
descriptioncaption1Regular · stone-400동일
iconh-4 w-4 · variant 색상동일
action button heighth-8 (32px) · button2Medium≥44pt hit area (hitSlop 또는 row 전체 hit area)
close positionabsolute -left-2 -top-2사용 안 함 — swipe-to-dismiss로 대체
close sizeh-5 w-5 · rounded-full · bg-white · ring-1 · shadow-md
close visibilityopacity-0group-hover:opacity-100— (hover 없음)
dismiss자동 4s/6s · close 버튼 클릭 · hover 시 pause자동 4s/6s · swipe-to-dismiss (위/아래/좌/우) · 탭 dismiss · hover-pause 없음

동작 규칙

항목
동시 표시 최대1개 (TOAST_LIMIT = 1)
기본 duration3초
지속 toastduration: Infinity
위치desktop: bottom-right / mobile: top
닫기 방식swipe (우) · Close 버튼 · duration 만료
진입slide-in-from-bottom-2 · fade-in
퇴장slide-out-to-right-full · fade-out-80

Usage

// 기본 (title만)
toast({ title: "링크가 복사되었습니다" })

// description 포함
toast({
  title: "마이크 연결됨",
  description: deviceName,
})

// destructive
toast({
  title: "마이크 접근이 차단되었습니다",
  description: "브라우저 설정에서 마이크 권한을 허용해 주세요.",
  variant: "destructive",
})

// action 포함
toast({
  title: "노트가 삭제되었습니다",
  description: "팀 주간 회의",
  action: <ToastAction altText="실행 취소">실행 취소</ToastAction>,
})

// 지속 toast
const { dismiss } = toast({
  title: "연결이 끊겼습니다",
  variant: "destructive",
  duration: Infinity,
})
dismiss()

A11y

  • aria-live="polite" (default/success) / aria-live="assertive" (destructive)
  • Focus를 빼앗지 않음 — 현재 작업 방해 금지
  • Close 버튼: aria-label="닫기" 필수

Do / Don't

  • Do: 상태 변경 결과, 짧은 피드백에 사용
  • Do: duration: Infinity는 사용자가 직접 해소해야 하는 상태에만
  • Do: action은 1개, 레이블은 동사 단어 ("실행 취소", "설정 열기")
  • Don't: Critical error (사용자 액션 필수)에 Toast 단독 사용 금지 → AlertDialog
  • Don't: title 없이 description만 사용 금지
  • Don't: 여러 개 쌓지 않음 — TOAST_LIMIT 1 준수

On this page