컴포넌트
Tooltip
요소에 대한 짧은 설명을 표시합니다.
모션
100ms 동안 작은 확대와 투명도 변화를 적용합니다. 움직임 감소 설정에서는 전환을 생략합니다. 공통 모션 규칙을 따릅니다.
설치
pnpm dlx ply-ui add tooltip공통 설치 설정을 먼저 적용합니다.
사용법
Provider.delay로 표시 지연을 정하고 Positioner로 위치를 지정합니다.
필수 안내나 클릭해야 하는 콘텐츠는 Tooltip 대신 본문이나 Popover에 넣으세요.
구성
| 구성 요소 | 역할 |
|---|---|
Provider | 여러 툴팁의 표시 지연을 설정합니다. |
Root | 툴팁 하나의 상태를 관리합니다. |
Trigger | 마우스 또는 키보드 포커스로 설명을 표시하는 대상입니다. |
Portal / Positioner / Popup | 설명의 위치와 표면을 구성합니다. |
Arrow | 대상 방향을 가리키는 표시입니다. |
구현 코드
components/ui/tooltip.tsx
"use client";
import type { ComponentProps } from "react";
import { Tooltip as Primitive } from "@base-ui/react/tooltip";
import { withClassName } from "../../lib/cx";
import "./tooltip.css";
// 동작과 접근성은 Base UI가 담당합니다. 이 파일은 스타일 연결만 담당합니다.
function TooltipTrigger({
className,
...props
}: ComponentProps<typeof Primitive.Trigger>) {
return (
<Primitive.Trigger
{...props}
className={withClassName("rbx-button", className)}
/>
);
}
function TooltipPopup({
className,
...props
}: ComponentProps<typeof Primitive.Popup>) {
return (
<Primitive.Popup
{...props}
className={withClassName("rbx-tooltip", className)}
/>
);
}
function TooltipPositioner({
className,
...props
}: ComponentProps<typeof Primitive.Positioner>) {
return (
<Primitive.Positioner
{...props}
className={withClassName("rbx-positioner", className)}
/>
);
}
function TooltipArrow({
className,
...props
}: ComponentProps<typeof Primitive.Arrow>) {
return (
<Primitive.Arrow
{...props}
className={withClassName("rbx-popup-arrow", className)}
/>
);
}
// Root/Portal 등 스타일 없는 파트와 제네릭 API는 원본을 그대로 보존합니다.
export const Tooltip = {
...Primitive,
Trigger: TooltipTrigger,
Popup: TooltipPopup,
Positioner: TooltipPositioner,
Arrow: TooltipArrow,
};
components/ui/tooltip.css
@import "./button.css";
/* Tooltip: 공통 구조는 theme.css, 컴포넌트 전용 조정은 아래에 작성합니다. */
.rbx-tooltip {
padding: 8px 12px;
border-radius: 8px;
background: var(--rbx-color-content-emphasis);
color: var(--rbx-color-surface-0);
font-size: 0.875rem;
box-shadow: 0 4px 16px var(--rbx-color-common-shadow);
max-width: 280px;
}
.rbx-tooltip {
transform-origin: var(--transform-origin);
transition:
opacity var(--rbx-motion-duration-feedback) var(--rbx-motion-ease-enter),
scale var(--rbx-motion-duration-feedback) var(--rbx-motion-ease-enter);
}
.rbx-tooltip:is([data-starting-style], [data-ending-style]) {
opacity: 0;
scale: var(--rbx-motion-scale-overlay);
}
.rbx-tooltip[data-ending-style] {
transition-timing-function: var(--rbx-motion-ease-exit);
}