Skip to content

Tooltip Primitive

Primitive Tooltip은 Popup을 pointer-enter 및 hover-away 동작과 조합합니다.

Usage

tsx
import {
  Tooltip,
  TooltipTrigger,
  TooltipContent,
  useTooltip,
} from '@suis-ui/primitives';

권장 primitive 구조는 trigger anchor와 portal에 렌더링되는 tooltip content를 조합하는 형태입니다.

text
Tooltip
├── TooltipTrigger
│   └── HTMLElement child
└── TooltipContent
    └── Portal
        └── tooltip content
tsx
<Tooltip openDelay={300} closeDelay={100} placement="top">
  <Tooltip.Trigger>
    <button type="button">Hover me</button>
  </Tooltip.Trigger>
  <Tooltip.Content>
    Tooltip content
  </Tooltip.Content>
</Tooltip>

Props

Delay

이름타입기본값간단한 설명
openDelaynumber0Pointer enter 이후 열리기 전 delay입니다.
closeDelaynumber0Pointer leave 이후 닫히기 전 delay입니다.
childrenJSX.Element필수Tooltip composition입니다.

Tooltip은 Popup 위에 구성되므로 Popup의 state와 positioning props를 함께 받습니다.

이름타입기본값간단한 설명
openbooleanfalsePopup open request value입니다.
placementPlacementFloating UI default선호 placement입니다.
strategyStrategyFloating UI defaultCSS positioning strategy입니다.
offsetOffsetOptions-Offset middleware를 활성화합니다.
shiftShiftOptions | boolean-Shift middleware를 활성화합니다.
flipFlipOptions | boolean-Flip middleware를 활성화합니다.
autoUpdateAutoUpdateOptions | booleantrueLayout이 바뀔 때 position을 다시 계산합니다.
middlewareMiddleware[]-추가 Floating UI middleware입니다.

Component

Tooltip.Trigger

DOM child를 popup anchor로 등록하고, pointer enter 시 openDelay 이후 열며 hover away 시 closeDelay 이후 닫습니다.

Trigger가 anchor를 등록하면 anchor는 tooltip content id를 가리키는 aria-describedby를 받습니다.

이름타입기본값간단한 설명
childrenJSX.Element-Trigger anchor로 등록할 DOM element입니다.

Tooltip.Content

Popup content를 portal에 렌더링하고 role="tooltip"을 적용하며 생성된 id를 받습니다.

이름타입기본값간단한 설명
asTdivContent로 렌더링할 element 또는 component입니다.
childrenJSX.Element-Tooltip 안에 렌더링할 내용입니다.
선택한 element propsOmit<ComponentProps<T>, 'children' | 'style'>-Content element로 전달되는 props입니다. 계산된 popup style과 함께 merge됩니다.

Hooks

useTooltip

useTooltip은 Tooltip provider 아래에서 tooltip id, delay 설정, popup 상태와 open action을 함께 읽을 때 사용합니다.

Signature

ts
const [context, actions] = useTooltip();
ts
const [context, actions]: readonly [
  {
    id: string;
    openDelay?: number;
    closeDelay?: number;
    anchor: Element | null;
    element: HTMLElement | null;
    position: ComputePositionReturn | null;
    open: boolean;
    mount: boolean;
  },
  {
    requestOpen: (open: boolean) => void;
  },
] = useTooltip();

Tooltip provider 밖에서 호출하면 context를 찾을 수 없어 error가 발생합니다.

Context

context는 Tooltip context와 Popup context를 merge한 값입니다.

이름타입설명
context.idstringTooltip content에 적용되고 trigger의 aria-describedby가 참조하는 고유 id입니다.
context.openDelaynumberPointer enter 이후 열리기 전 delay입니다.
context.closeDelaynumberPointer leave 이후 닫히기 전 delay입니다.
context.anchorElement | nullTooltip.Trigger가 등록한 popup anchor입니다.
context.elementHTMLElement | nullTooltip.Content가 portal에 렌더링한 tooltip element입니다.
context.positionComputePositionReturn | nullFloating UI가 계산한 tooltip position입니다.
context.openboolean가장 최근에 요청된 tooltip open state입니다.
context.mountbooleanTooltip content가 실제로 portal에 렌더링되는지 나타냅니다.

Tooltip을 확장할 때는 위 표의 id, delay, popup 상태만 사용하세요.

Actions

이름타입설명
actions.requestOpen(open: boolean) => voidTooltip popup의 open state를 요청합니다.

Behavior

기본 Tooltip.Trigger가 pointer enter와 hover away 동작을 이미 처리합니다. useTooltip은 그 동작을 재사용하면서 custom trigger나 content에서 상태를 읽거나 open state를 직접 제어해야 할 때 사용하세요.

openDelaycloseDelay는 기본 Tooltip.Trigger의 pointer 동작에서 사용됩니다. 직접 requestOpen(true) 또는 requestOpen(false)를 호출하면 delay 없이 즉시 open request를 보냅니다.

idTooltip.Content에 적용되고 trigger의 aria-describedby에 연결됩니다. Custom content를 만들 때도 같은 id를 유지해야 screen reader 연결이 유지됩니다.

Example

tsx
const TooltipStateLabel = () => {
  const [context] = useTooltip();

  return (
    <span data-open={context.open}>
      {context.open ? 'Open' : 'Closed'}
    </span>
  );
};

Examples

Basic Tooltip

tsx
<Tooltip placement="top" offset={6}>
  <Tooltip.Trigger>
    <button type="button">Hover me</button>
  </Tooltip.Trigger>
  <Tooltip.Content>
    Tooltip content
  </Tooltip.Content>
</Tooltip>

Delayed Tooltip

tsx
<Tooltip openDelay={300} closeDelay={100} placement="right">
  <Tooltip.Trigger>
    <button type="button">Help</button>
  </Tooltip.Trigger>
  <Tooltip.Content>
    Opens after a short delay.
  </Tooltip.Content>
</Tooltip>

Custom Content Element

tsx
<Tooltip placement="bottom" shift flip>
  <Tooltip.Trigger>
    <button type="button">Status</button>
  </Tooltip.Trigger>
  <Tooltip.Content as="section" aria-label="Status details">
    The job is running.
  </Tooltip.Content>
</Tooltip>