# Toast 작업 결과를 잠깐 알려주고 스스로 사라지는 알림입니다. > 원본: `03_ASSET_GUIDE/catalog/toast.js` · CSS: `03_ASSET_GUIDE/styles/elements/toast.css` > kind `component` · category `overlay` · status `stable` · specSource `measured` --- ## 1. 구성 어두운 칩 하나입니다. **Message** 만 필수이고 앞의 **Icon**, 뒤의 **Action** 과 **Close** 는 선택입니다. 앱의 어느 화면 위에서도 대비를 확보하도록 칩은 두 테마 모두 어둡게 유지합니다. ``` ┌────────────────────────────────────────────┐ │ ⊗ 파일을 올리지 못했어요 다시 시도 ✕ │ └────────────────────────────────────────────┘ ①② ③ ④ ⑤ ``` | # | 요소 | 필수 | 클래스 | 설명 | |---|---|---|---|---| | ① | Container | 필수 | `atom-toast` | `--atom-bg-tooltip` 칩. 폭 340px, 최소 높이 44px. | | ② | Icon | tone 을 쓰면 필수 | `atom-toast__icon` | tone 을 쓰면 필수입니다. 색만으로 성공·실패를 구분하지 않기 위한 요소입니다. | | ③ | Message | 필수 | `atom-toast__message` | 알림 문구. 두 줄까지 늘어나고 그 뒤로는 잘립니다. | | ④ | Action | 선택 | `atom-toast__action` | 선택. 하나만 둡니다. 있으면 자동 소멸을 끕니다. | | ⑤ | Close | 자동 소멸이 없으면 필수 | `atom-toast__close` | 자동으로 사라지지 않는 Toast 에는 필수입니다. | | — | Group | 필수(띄울 때) | `atom-toast-group` | live region 이자 위치를 정하는 컨테이너. Toast 보다 먼저 페이지에 존재해야 합니다. | --- ## 2. 종류 / 크기 ### 치수 | 대상 | 값 | | --- | --- | | 폭 | 340px · `max-width: 100%` 로 좁은 화면에서 줄어듭니다 | | 최소 높이 | 44px | | 패딩 | 13px 16px (`--atom-x4`) | | 모서리 | `--atom-radius-r2` (8px) | | 폰트 | 13px / line-height 1.45 | | Icon ↔ Message 간격 | `--atom-x2` (8px) | | Message ↔ Action 간격 | 16px (`--atom-x2` gap + Action 의 8px 마진) | | Action | 13px / 700 · `--atom-fg-tooltip` · underline | | 그림자 | `--atom-shadow-s2` | 폭은 340px 이지만 `max-width: 100%` 가 함께 있어 좁은 화면에서는 컨테이너 폭까지 줄어듭니다. 좌우 여백은 `atom-toast-group` 의 `padding-inline: var(--atom-x4)` 가 만듭니다. 최소 높이 44px 은 Action 의 터치 타깃에서 나온 값입니다. Action 과 Close 는 `align-self: stretch` 와 음수 블록 마진으로 칩 높이를 그대로 채우므로, 글자 높이(19px)가 아니라 44px 이 눌리는 영역입니다. 컨테이너 `gap` 이 8px 인 것은 Icon 을 Message 에 붙이기 위한 것입니다. 양쪽 모두 16px 이면 아이콘이 Message 와 떨어진 별개 항목처럼 보입니다. Message ↔ Action 의 16px 는 Action 의 `margin-inline-start` 8px 가 되돌려 줍니다. ### Tone `neutral` · `positive` · `critical` 세 가지입니다. tone 은 **배경이 아니라 아이콘 색**을 바꿉니다. 칩은 세 tone 모두 `--atom-bg-tooltip` 을 그대로 씁니다. | Tone | 아이콘 | 아이콘 색 | | --- | --- | --- | | `neutral` (기본) | `#atom-i-info` (선택) | `--atom-fg-tooltip` | | `positive` | `#atom-i-check-circle` | `--atom-fg-positive` | | `critical` | `#atom-i-x-circle` | `--atom-fg-critical` | tone 마다 배경색을 두면 라이트·다크 각각 세 쌍, 여섯 조합의 대비를 따로 맞춰야 합니다. 그래서 칩은 어두운 색 하나로 고정하고 **아이콘 모양**으로 tone 을 구분합니다. 색각 이상 사용자에게도 같은 정보가 전달됩니다. seed 는 배경색을 나누지만, ATOM 은 Toast 가 앱의 어느 화면 위에도 뜬다는 점을 우선했습니다. > [!WARNING] > **tone 을 쓰면 아이콘은 필수입니다** > `--tone_positive` · `--tone_critical` 은 아이콘 색만 바꿉니다. 아이콘 없이 tone 만 > 지정하면 화면에 아무 차이도 나타나지 않습니다. ### Action 오른쪽 끝에 텍스트 버튼 하나를 둘 수 있습니다. Action 이 있으면 자동 소멸을 끄고 `__close` 를 함께 둡니다. 이유는 [접근성](#6-접근성) 을 보세요. Action 색은 `--atom-fg-tooltip` 입니다. 밝은 브랜드색을 쓸 수 없어서 굵기(700)와 밑줄, 위치로 버튼임을 알립니다. > [!NOTE] > **브랜드색을 쓰지 않는 이유** > `--atom-bg-tooltip` 은 두 테마 모두 어둡습니다. 그래서 테마에 따라 밝기가 뒤집히는 > 토큰을 여기에 쓸 수 없습니다. `--atom-primary-500` 은 라이트 3.4:1 · 다크 4.2:1 로 > 13px 텍스트 기준 4.5:1 에 미달하고, `--atom-primary-200` 은 라이트에서 10.3:1 이지만 > 다크에서 `#202564` 로 어두워져 1.25:1 이 됩니다. 두 테마 모두 밝게 남는 토큰은 > `--atom-fg-tooltip` 하나뿐입니다. ### 지속 시간 CSS 에는 노출 시간이 없습니다. 스크립트가 정할 값이고, 레퍼런스가 크게 갈립니다. | 시스템 | 값 | | --- | --- | | Codeit Toast | 2~3초 | | Ant Message | 3초 | | seed Snackbar | **4초** (긴 문구는 연장, 사용자가 만지면 타이머 정지) | | Ant Notification | 4.5초 | | Spectrum | **자동 소멸 기본 꺼짐**, 켤 경우 최소 5초 | > [!NOTE] > **ATOM 의 값** > **액션이 없으면 4초, 액션이 있으면 자동으로 사라지지 않습니다.** 4초는 한국어 한 > 줄(약 20자)을 읽고 판단할 수 있는 최소 시간이고, seed 와 같은 값입니다. 마우스를 > 올리거나 포커스가 들어오면 타이머를 멈춥니다. ### 위치 기본은 화면 아래 중앙입니다. 위치는 개별 Toast 가 아니라 `atom-toast-group` 이 결정합니다. 화면에 붙일 때는 `--anchor_screen`(fixed), 폰 프레임이나 특정 영역 안에 둘 때는 `--anchor_parent`(absolute) 를 씁니다. | 모디파이어 | 결과 | | --- | --- | | `--placement_bottom` | 기본. 아래에서 `--atom-x4`(16px) | | `--placement_top` | 위에서 `--atom-x4`(16px) | | `--offset_raised` | 아래에서 `--atom-x14`(56px). 하단 내비게이션이나 FAB 위로 올립니다 | 그룹은 화면 폭을 가로지르므로 `pointer-events: none` 을 두고 Toast 에만 `auto` 를 되돌려 줍니다. 그렇지 않으면 화면 아래쪽 전체가 클릭을 가로챕니다. `z-index` 는 80 으로, 셸(최대 60)과 Dialog 보다 위입니다. Dialog 안에서 일어난 일을 알리는 Toast 가 Dialog 에 가려지지 않게 하기 위해서입니다. 플로팅 액션 버튼(`fab`)이나 하단 내비게이션(`bottom-navigation`)이 있으면 `--offset_raised` 로 그 위에 놓아 가리지 않게 합니다. ### 여러 개가 쌓일 때 새 Toast 는 언제나 그룹의 마지막에 붙습니다. `bottom` 배치는 위로, `top` 배치는 아래로 자라고, 어느 쪽이든 **가장 최근 것이 붙어 있는 화면 가장자리에 가장 가깝습니다.** 권장은 **한 번에 하나**입니다. 여러 개가 겹치면 무엇을 읽어야 할지 알 수 없고, live region 이 연달아 읽혀 소음이 됩니다. CSS 는 4개째부터 `display: none`(`:nth-last-child(n + 4)`)으로 가립니다. 이는 Toast 가 화면을 덮지 않게 하는 안전장치이며, 순서 관리는 스크립트가 맡습니다. ### 문구 길이 Message 는 기본으로 **두 줄까지** 늘어나고 그 뒤로는 잘립니다 (`-webkit-line-clamp: 2`). 한 줄로 고정하려면 `--lines_1` 을 쓰면 말줄임으로 처리됩니다. 한국어 줄바꿈은 `word-break: keep-all` 로 단어 단위입니다. 두 줄을 넘겨 잘리면 **문구를 줄입니다.** 칩이 커지면 아래 화면을 가리므로 높이를 늘리지 않고 자릅니다. ### 모션 진입은 8px 이동 + 페이드(`--atom-duration-base` · `--atom-ease-out`), 퇴장은 페이드만 (`--atom-duration-fast`)입니다. 이동 방향은 배치를 따릅니다. `bottom` 은 아래에서, `top` 은 위에서 들어옵니다. - 모션은 `[data-state="entering"]` · `[data-state="exiting"]` 에만 걸립니다. 카탈로그 카드나 문서 스테이지에 정적으로 놓인 Toast 가 렌더될 때마다 진입 애니메이션을 다시 재생하지 않게 하기 위한 것입니다. - `prefers-reduced-motion: reduce` 에서는 이동을 없애고 페이드만 남깁니다. `base.css` 가 모든 애니메이션을 0.01ms 로 줄이므로 8px 이동이 순간적으로 튀어 보이기 때문입니다. - 그때도 `animationend` 는 발생합니다. 퇴장 애니메이션에 정리(DOM 제거)를 걸어 둔 스크립트가 동작하도록 `animation: none` 을 쓰지 않습니다. ### 클래스 계약 `styles/elements/toast.css` 헤더와 원본 `registry.json` `css.blocks` 기준입니다. 클래스가 없는 값(—)은 기본 스타일 그대로입니다. | 대상 | Prop | 값 | 클래스 | |---|---|---|---| | `atom-toast` | `tone` | `neutral` · `positive` · `critical` | — · `--tone_positive` · `--tone_critical` | | `atom-toast` | `singleLine` | `false` · `true` | — · `--lines_1` | | `atom-toast-group` | `placement` | `bottom` · `top` | — · `--placement_top` | | `atom-toast-group` | (구현 `anchor`) | 없음 · `screen` · `parent` | — · `--anchor_screen` · `--anchor_parent` | | `atom-toast-group` | (구현 `raised`) | `false` · `true` | — · `--offset_raised` | 상태 선택자: `atom-toast[data-state="entering\|exiting"]` · `__action` / `__close` 의 `:hover` · `:focus-visible` · `[disabled]` --- ## 3. 상태 | State | 표현 | 선택자 | | --- | --- | --- | | (속성 없음) | 정적 표시. 모션 없음 | — | | entering | 8px 이동 + 페이드 인 (`--atom-duration-base`) · `top` 은 위에서 | `[data-state="entering"]` | | exiting | 페이드 아웃 (`--atom-duration-fast`) | `[data-state="exiting"]` | | Action · Close hover | `opacity: 1` · 밑줄 2px | `:hover` | | Action · Close focus | 2px `--atom-fg-tooltip` 링, offset `-2px` | `:focus-visible` | | Action · Close disabled | `opacity: 0.4` · `not-allowed` | `[disabled]` | --- ## 4. Props | Prop | Type | Default | 필수 | 설명 | |---|---|---|---|---| | `message` | `ReactNode` | | ● | 알림 문구입니다. 두 줄까지 보이고 그 뒤로는 잘립니다. | | `tone` | `"neutral" \| "positive" \| "critical"` | `"neutral"` | | 아이콘 색을 결정합니다. 배경은 바뀌지 않습니다. | | `icon` | `ReactNode` | | | 선행 아이콘입니다. `tone` 을 `neutral` 이 아닌 값으로 주면 필수입니다. | | `action` | `{ label: string, onClick: () => void }` | | | 액션 버튼입니다. 하나만. 주면 `duration` 이 자동으로 `null` 이 됩니다. | | `duration` | `number \| null` | `4000` | | 자동 소멸까지의 ms 입니다. `null` 이면 사라지지 않습니다. | | `dismissible` | `boolean` | 자동 | | 닫기 버튼입니다. `duration: null` 이면 필수입니다. | | `singleLine` | `boolean` | `false` | | `--lines_1` 을 붙여 한 줄 + 말줄임으로 고정합니다. | | `placement` | `"bottom" \| "top"` | `"bottom"` | | 그룹의 속성입니다. 개별 Toast 가 아니라 컨테이너가 위치를 정합니다. | ### Parts (compound) | Part | 요소 | 설명 | |---|---|---| | `Toast` | `