registry:component

Global Tooltip

v1.0.0ga

Viewport-aware tooltip system with shared motion layer.

Registry Endpoint
Open JSON

https://registry.aavya.com/r/ui-global-tooltip.json

npx shadcn@latest add https://registry.aavya.com/r/ui-global-tooltip.json

Live Preview
Usage Snippet
import GlobalTooltip from '@/components/ui/global-tooltip.tsx'

export default function Example() {
  return (
    <div className="p-6">
      <GlobalTooltip />
    </div>
  )
}
Source Preview
'use client'

import * as React from 'react'

import { createPortal } from 'react-dom'
import { motion, AnimatePresence, LayoutGroup, type Transition } from 'motion/react'

import { cn } from '@/lib/utils'

type Side = 'top' | 'bottom' | 'left' | 'right'

type Align = 'start' | 'center' | 'end'

type TooltipData = {
  content: React.ReactNode
  rect: DOMRect
  side: Side
  sideOffset: number
  align: Align
  alignOffset: number
  id: string
  arrow: boolean
}

type GlobalTooltipContextType = {
  showTooltip: (data: TooltipData) => void
  hideTooltip: () => void
  currentTooltip: TooltipData | null
  transition: Transition
  globalId: string
}

const GlobalTooltipContext = React.createContext<GlobalTooltipContextType | undefined>(undefined)

const useGlobalTooltip = () => {
  const context = React.useContext(GlobalTooltipContext)

  if (!context) {
    throw new Error('useGlobalTooltip must be used within a TooltipProvider')
  }

  return context
}

type TooltipPosition = {
  x: number
  y: number
  transform: string
  initial: { x?: number; y?: number }
}

function getTooltipPosition({
  rect,
  side,
  sideOffset,
  align,
  alignOffset
}: {
  rect: DOMRect
  side: Side
  sideOffset: number
  align: Align
  alignOffset: number
}): TooltipPosition {
  switch (side) {
    case 'top':
      if (align === 'start') {
        return {
          x: rect.left + alignOffset,