Aesthe UI

Floating Dock

A macOS-style animated floating dock with smooth hover magnification effects

Overview

A beautiful macOS-inspired floating dock component with smooth magnification effects. Icons elegantly scale and animate based on mouse proximity, creating an intuitive and delightful user experience. Built with Framer Motion for fluid spring animations.

Preview


Installation

Dependencies

npm install motion @tabler/icons-react

The component requires:

  • motion (Framer Motion) - For smooth animations and spring physics
  • @tabler/icons-react - For icons (or use your preferred icon library)
  • Next.js - For the Link component (can be adapted for other frameworks)

Usage

Basic Implementation

import { FloatingDock } from '@/components/aesthe-ui/floating-dock/floating-dock'

export default function MyPage() {
  return (
    <div>
      {/* Your page content */}
      <FloatingDock />
    </div>
  )
}

Customize the dock by modifying the links array in the FloatingDockCore component:

const links: LinkProps[] = [
  {
    label: 'Dashboard',
    href: '/dashboard',
    icon: <LayoutDashboard className="h-full w-full text-neutral-600 dark:text-neutral-300" />,
  },
  {
    label: 'Projects',
    href: '/projects',
    icon: <FolderKanban className="h-full w-full text-neutral-600 dark:text-neutral-300" />,
  },
  {
    label: 'Messages',
    href: '/messages',
    icon: <MessageSquare className="h-full w-full text-neutral-600 dark:text-neutral-300" />,
  },
  // Add more links as needed
]

Standalone Component

If you want to make the links configurable via props:

interface FloatingDockProps {
  items: LinkProps[]
}

export const FloatingDock = ({ items }: FloatingDockProps) => {
  return (
    <div className="flex h-screen items-center justify-center">
      <FloatingDockCore links={items} />
    </div>
  )
}

Component Structure

Main Components

  1. FloatingDock - Wrapper component that centers the dock
  2. FloatingDockCore - Core dock container with mouse tracking
  3. LinkItem - Individual dock item with magnification logic

Type Definition

type LinkProps = {
  label: string      // Tooltip label
  href: string       // Navigation URL
  icon: React.ReactNode  // Icon component
}

Customization

Positioning

Change the dock position by modifying the className:

// Bottom center (default)
className="fixed inset-x-0 bottom-10 mx-auto ..."

// Top center
className="fixed inset-x-0 top-10 mx-auto ..."

// Bottom left
className="fixed bottom-10 left-10 ..."

// Bottom right
className="fixed bottom-10 right-10 ..."

Size Adjustments

Modify the size ranges in the useTransform calls:

// Smaller icons (30-60px range)
const widthTransform = useTransform(distance, [-150, 0, 150], [30, 60, 30])
const heightTransform = useTransform(distance, [-150, 0, 150], [30, 60, 30])

// Larger icons (50-100px range)
const widthTransform = useTransform(distance, [-150, 0, 150], [50, 100, 50])
const heightTransform = useTransform(distance, [-150, 0, 150], [50, 100, 50])

Animation Physics

Adjust the spring physics for different feels:

// Bouncier animation
const width = useSpring(widthTransform, { mass: 0.2, damping: 8, stiffness: 150 })

// Smoother animation
const width = useSpring(widthTransform, { mass: 0.05, damping: 15, stiffness: 80 })

Magnification Distance

Change the distance threshold for magnification effect:

// Shorter range (100px)
const widthTransform = useTransform(distance, [-100, 0, 100], [40, 80, 40])

// Longer range (200px)
const widthTransform = useTransform(distance, [-200, 0, 200], [40, 80, 40])

Styling

Customize colors and appearance:

// Dock container
className="... bg-blue-100 dark:bg-blue-900"

// Icon background
className="... bg-gradient-to-br from-purple-400 to-pink-400"

// Tooltip
className="... bg-black text-white border-none"

Advanced Features

For external links, replace Next.js Link with a regular anchor:

<a 
  href={link.href}
  target="_blank"
  rel="noopener noreferrer"
>
  {/* icon content */}
</a>

Active State

Add active state indication:

const pathname = usePathname() // Next.js 13+
const isActive = pathname === link.href

<motion.div
  className={cn(
    "relative flex aspect-square items-center justify-center rounded-full",
    isActive 
      ? "bg-primary text-primary-foreground" 
      : "bg-gray-200 dark:bg-neutral-700"
  )}
  style={{ width, height }}
>

Click Actions

Add click handlers instead of navigation:

type LinkProps = {
  label: string
  onClick: () => void
  icon: React.ReactNode
}

// In LinkItem component:
<button
  onClick={link.onClick}
  onMouseEnter={() => setHover(true)}
  onMouseLeave={() => setHover(false)}
>
  {/* icon content */}
</button>

Tips

  • Keep the number of icons between 4-8 for best visual balance
  • Use consistent icon styles (all outline or all filled)
  • Test the magnification effect with different mouse speeds
  • Consider mobile responsiveness (dock may not work well on touch devices)
  • Use semantic labels for accessibility
  • Ensure sufficient color contrast for icons in both light and dark modes

Browser Support

Works in all modern browsers that support:

  • CSS Grid and Flexbox
  • CSS backdrop-filter
  • ES6+ JavaScript
  • Framer Motion's animation features

For older browsers, consider adding appropriate polyfills or fallbacks.