# Tooltip 요소를 가리켰을 때 짧은 보충 설명을 띄우는 말풍선입니다. > 원본: `03_ASSET_GUIDE/catalog/tooltip.js` · CSS: `03_ASSET_GUIDE/styles/elements/tooltip.css` (헤더 이름 "Help Bubble (Tooltip)") > kind `component` · category `overlay` · status `stable` · specSource `measured` > 함께 필요한 CSS: `button` (데모의 트리거) --- ## 1. 구성 툴팁은 두 겹으로 구성됩니다. 위치의 기준이 되는 **Root** 가 트리거와 말풍선을 함께 감싸고, 그 안에서 **Container** 가 트리거 옆에 떠 있습니다. Title 과 Arrow 는 선택 사항입니다. ``` ┌────────────────────────────┐ │ 다음 갱신일 4월 3일 │ ② ③ │ 갱신 3일 전에 알림을 보내드려요 │ ④ └─────────────┬──────────────┘ ▼ ⑤ [ ⓘ ] ⑥ └─────────────── ① Root ───────────────┘ ``` | # | 요소 | 필수 | 클래스 | 설명 | |---|---|---|---|---| | ① | Root | 필수(위치를 잡을 때) | `atom-tooltip__root` | 트리거와 말풍선을 감싸는 위치 기준입니다. `position: relative` 가 여기 걸립니다. | | ② | Container | 필수 | `atom-tooltip` | 말풍선 본체. 두 테마 모두 어두운 칩입니다. | | ③ | Title | 선택 | `atom-tooltip__title` | 굵은 첫 줄. 없어도 됩니다. | | ④ | Description | 필수 | (클래스 없음) | 설명 본문. | | ⑤ | Arrow | 선택 | `atom-tooltip__arrow` | 대상을 가리키는 꼬리. 없어도 나머지 배치는 그대로입니다. | | ⑥ | Trigger | 필수 | (트리거 자신의 클래스) | 툴팁을 여는 대상. 툴팁의 일부가 아니라 툴팁이 붙는 쪽입니다. | --- ## 2. 종류 / 크기 ### Placement 대상의 어느 쪽에 붙을지를 정합니다. `top` 이 기본이고 `bottom` · `start` · `end` 가 있습니다. Arrow 는 항상 대상을 향하도록 반대편에 붙고, 이 뒤집기는 Root 밖에 홀로 놓인 말풍선에도 적용됩니다. | 값 | 말풍선 위치 | Arrow | | --- | --- | --- | | `top` | 대상 위 (기본) | 아래쪽 가운데 | | `bottom` | 대상 아래 | 위쪽 가운데 | | `start` | 대상의 글줄 시작 쪽 | 오른쪽 가운데 | | `end` | 대상의 글줄 끝 쪽 | 왼쪽 가운데 | `start` · `end` 는 물리 방향이 아니라 글줄 방향입니다. 좌우 반전 언어에서도 "대상 앞/뒤" 라는 뜻이 유지되도록 `inset-inline` 으로 잡았습니다. > [!WARNING] > **화면 밖으로 나가는 것은 CSS 가 막지 못합니다** > 툴팁이 뷰포트 가장자리를 넘으면 반대편으로 뒤집히거나 안쪽으로 밀려야 합니다. CSS 로는 > 잘림 여부를 알 수 없으므로, 실제 구현에서는 좌표를 재는 floating 라이브러리가 > `--placement_*` 와 `--align_*` 을 바꿉니다. 스크립트 없이 쓸 때는 가장자리 근처 > 요소에 방향을 직접 지정하세요. ### Align 네 방향은 어느 쪽인지만 정하고, 그 변을 따라 어디에 서는지는 `--align_start` · `--align_end` 가 정합니다. 지정하지 않으면 대상 가운데입니다. 네 방향 × 세 정렬로 열두 자리가 나옵니다. 툴팁이 대상보다 넓으면 가운데 정렬 시 컨테이너 밖으로 넘칩니다. 이때는 가까운 쪽 끝으로 정렬합니다. floating 라이브러리가 안쪽으로 밀 때도 같은 방식입니다. Arrow 도 가장자리에서 12px 안쪽으로 함께 옮겨져 모서리에 걸리지 않습니다. ### 최대 너비와 줄바꿈 Container 의 최대 너비는 **240px**, 폰트는 13px 입니다. 13px 기준 한글 약 17자가 한 줄이므로 두 줄이면 서른 자 남짓입니다. 그보다 긴 내용은 툴팁에 담지 않습니다. 한국어가 어절 중간에서 끊기지 않도록 `word-break: keep-all` 이 걸려 있고, 끊을 곳이 없는 긴 문자열만 `overflow-wrap: break-word` 로 넘깁니다. `.atom-break-keep` 은 붙이지 않습니다. ### 트리거와의 관계 `atom-tooltip__root` 가 트리거와 말풍선을 함께 감싸 `position: relative` 기준을 만들고, `--placement_*` 는 그 안에서만 좌표를 잡습니다. Root 밖에 놓으면 말풍선은 흐름 안의 칩으로 표시됩니다. 문서 스테이지와 카드 프리뷰가 이 형태입니다. ```html ``` Root 는 목록 안이나 스크롤 컨테이너 안에서 잘릴 수 있습니다. 잘리면 안 되는 자리에서는 말풍선을 본문 끝으로 옮겨 띄우고 좌표만 계산해 붙이는 편이 안전합니다. 이때 위치는 스크립트가 계산합니다. ### 치수 | 대상 | 값 | | --- | --- | | Container 최대 너비 | 240px | | Container 패딩 | `--atom-x2` `--atom-x3` (8px 12px) | | 폰트 | 13px / line-height 1.5 | | Arrow | 12×6px (`start` · `end` 는 6×12px), Container 와 1px 겹침 | | 대상과의 간격 | 4px (Arrow 5px 를 더해 `calc(100% + 9px)`) | | Arrow 정렬 오프셋 | `--align_*` 일 때 가장자리에서 12px (`start` · `end` 배치는 10px) | ### 클래스 계약 `styles/elements/tooltip.css` 헤더와 원본 `registry.json` `css.blocks` 기준입니다. 클래스가 없는 값(—)은 기본 스타일 그대로입니다. | Prop | 값 | 클래스 | |---|---|---| | `placement` | `top` · `bottom` · `start` · `end` | — · `--placement_bottom` · `--placement_start` · `--placement_end` | | `align` | `start` · `center` · `end` | `--align_start` · — · `--align_end` | | `arrow` | `true` · `false` | `__arrow` 렌더 · 없음 | 상태 선택자: `[data-state="closed\|open"]` > [!NOTE] > `align` 의 기본값 `"center"` 는 Props 표에만 있고, CSS 헤더는 "centred on the trigger by default" 라고만 적어 > 기본값을 선언하지 않습니다(원본 registry `problems` — `props-default-not-in-css`). 동작은 같습니다. 클래스가 없으면 가운데입니다. --- ## 3. 상태 상태는 `data-state` 하나뿐이고, 값은 스크립트가 바꿉니다. 속성이 없으면 보이는 상태로 렌더되므로, 문서와 프리뷰의 정적 마크업에는 속성을 붙이지 않습니다. | 값 | 결과 | | --- | --- | | `closed` | display: none. 접근성 트리에서도 사라집니다 | | `open` | 보이면서 120ms 등장 모션이 한 번 재생됩니다 | | (속성 없음) | 보입니다. 정적 마크업용 | 모션은 `--atom-duration-fast`(120ms) 동안 투명도 0 → 1 과 4px 이동입니다. 이동 방향은 대상에서 멀어지는 쪽이라 placement 마다 다릅니다. `prefers-reduced-motion: reduce` 에서는 모션을 끄고 처음부터 최종 위치에 그립니다. > [!NOTE] > **여닫기는 트리거 쪽 스크립트가 처리합니다** > `:hover` 만으로는 "100ms 뒤에 열고, 대상과 말풍선 사이 4px 를 건너는 동안은 닫지 않는다" > 를 구현할 수 없습니다. 이 두 지연이 없으면 툴팁이 깜빡이므로, hover · focus · `Esc` 를 > 받아 `data-state` 를 바꾸는 일은 트리거 쪽 스크립트가 맡습니다. --- ## 4. Props | Prop | Type | Default | 필수 | 설명 | |---|---|---|---|---| | `content` | `ReactNode` | | ● | 툴팁에 담을 텍스트입니다. | | `title` | `ReactNode` | | | 굵은 첫 줄입니다. | | `placement` | `"top" \| "bottom" \| "start" \| "end"` | `"top"` | | 대상 기준 방향입니다. | | `align` | `"start" \| "center" \| "end"` | `"center"` | | 그 변을 따라 어디에 설지 정합니다. | | `arrow` | `boolean` | `true` | | 꼬리를 그릴지 여부입니다. | | `openDelay` | `number` | `100` | | 노출까지의 지연(ms)입니다. | | `closeDelay` | `number` | `300` | | 포인터가 떠난 뒤 닫기까지의 지연(ms)입니다. | | `open` | `boolean` | | | 제어 모드에서 노출 여부를 지정합니다. | ### Parts (compound) | Part | 요소 | 설명 | |---|---|---| | `Tooltip` | `` > 트리거 + `