my/ui

Command Palette

Search for a command to run...

All components

Magnified Doc Tooltip

tooltips

Ui-Layouts component.

responsive · 380px

Install

Same command in any shadcn project — React (Vite/CRA), Next.js, Remix, Astro, and more:

$npx shadcn@latest add https://your-domain/r/magnified-doc.json

Usage

"use client";

import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "@/registry/ui-layouts/magnified-doc";
import {
  AnimatePresence,
  motion,
  useMotionValue,
  useSpring,
  useTransform,
} from "motion/react";
import { useRef } from "react";

const dockItems = [
  { label: "Home", icon: "⌂" },
  { label: "Search", icon: "⌕" },
  { label: "Files", icon: "⊟" },
  { label: "Messages", icon: "✉" },
  { label: "Settings", icon: "⚙" },
];

function DockIcon({
  mouseX,
  label,
  icon,
}: {
  mouseX: ReturnType<typeof useMotionValue<number>>;
  label: string;
  icon: string;
}) {
  const ref = useRef<HTMLButtonElement>(null);

  const distance = useTransform(mouseX, (val) => {
    const bounds = ref.current?.getBoundingClientRect() ?? { x: 0, width: 0 };
    return val - bounds.x - bounds.width / 2;
  });

  const size = useSpring(useTransform(distance, [-80, 0, 80], [40, 60, 40]), {
    mass: 0.1,
    stiffness: 150,
    damping: 12,
  });

  return (
    <Tooltip>
      <TooltipTrigger asChild>
        <motion.button
          ref={ref}
          style={{ width: size, height: size }}
          className="flex items-center justify-center rounded-xl border border-border bg-background text-xl shadow-sm transition-colors hover:bg-muted focus:outline-none"
          aria-label={label}
        >
          {icon}
        </motion.button>
      </TooltipTrigger>
      <TooltipContent side="top" sideOffset={8}>
        <p className="text-xs font-medium">{label}</p>
      </TooltipContent>
    </Tooltip>
  );
}

export default function Demo() {
  const mouseX = useMotionValue(Infinity);

  return (
    <div className="flex min-h-[280px] flex-col items-center justify-end pb-10">
      <TooltipProvider delayDuration={0}>
        <motion.div
          onMouseMove={(e) => mouseX.set(e.pageX)}
          onMouseLeave={() => mouseX.set(Infinity)}
          className="flex h-16 items-end gap-2 rounded-2xl border border-border bg-background/80 px-4 pb-2 shadow-lg backdrop-blur-sm"
        >
          {dockItems.map((item) => (
            <DockIcon
              key={item.label}
              mouseX={mouseX}
              label={item.label}
              icon={item.icon}
            />
          ))}
        </motion.div>
      </TooltipProvider>
    </div>
  );
}

Component source

'use client';

import { cn } from '@/lib/utils';
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
import * as React from 'react';

const TooltipProvider = TooltipPrimitive.Provider;

const Tooltip = TooltipPrimitive.Root;

const TooltipTrigger = TooltipPrimitive.Trigger;

const TooltipContent = React.forwardRef<
  React.ElementRef<typeof TooltipPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
  <TooltipPrimitive.Portal>
    <TooltipPrimitive.Content
      ref={ref}
      sideOffset={sideOffset}
      className={cn(
        'z-50 overflow-hidden rounded-lg border dark:bg-neutral-800 bg-neutral-50 backdrop-filter dark:border-[#2C2C2C] backdrop-blur-lg dark:bg-[#1A1A1A]/95 px-4 py-3 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
        className
      )}
      {...props}
    />
  </TooltipPrimitive.Portal>
));
TooltipContent.displayName = TooltipPrimitive.Content.displayName;

export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };

Dependencies

motion@radix-ui/react-tooltip

Source: Ui-Layouts