# Footer-5

> A footer with interactive text that responds to pointer movement

A shadcn/ui block from the [@hexui](https://hexui.sh) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/hexui/footer-5).

- Page, with a live preview: https://shadcn.exchange/r/hexui/footer-5
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/hexui/footer-5-light-57f7ba16fa601112.png
- Registry item: https://hexui.sh/r/footer-5.json
- Categories: footer
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://hexui.sh/r/footer-5.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `motion`

## Files

### `registry/blocks/footer/footer-5/source/app/footer/page.tsx`

```tsx
import { SiteFooter } from "../../components/site-footer"

export default function Page() {
    return (
        <div className="flex flex-col w-full min-h-dvh items-center justify-center">
            <SiteFooter />
        </div>
    )
}
```

### `registry/blocks/footer/footer-5/source/components/site-footer.tsx`

```tsx
import Link from "next/link";
import { NavLinks } from "./nav-links";
import { FluidGradientText } from "./fluid-gradient-text"

const footerSections = [
  {
    title: "Product",
    links: [
      { label: "Features", href: "#" },
      { label: "Pricing", href: "#" },
      { label: "Case Studies", href: "#" },
      { label: "Changelog", href: "#" },
    ],
  },
  {
    title: "Company",
    links: [
      { label: "About Us", href: "#" },
      { label: "Careers", href: "#" },
      { label: "Blog", href: "#" },
      { label: "Contact", href: "#" },
    ],
  },
  {
    title: "Resources",
    links: [
      { label: "Documentation", href: "#" },
      { label: "API Reference", href: "#" },
      { label: "Guides", href: "#" },
      { label: "Support", href: "#" },
    ],
  },
  {
    title: "Legal",
    links: [
      { label: "Terms of Service", href: "#" },
      { label: "Privacy Policy", href: "#" },
      { label: "Cookie Settings", href: "#" },
    ],
  },
];

export function SiteFooter() {
  return (
    <footer className="relative w-full overflow-visible pt-0 xl:pt-32">
      {/* Decorative oversized gradient wordmark, shown only on xl+ and shifted up so it
          overflows behind the footer bar. Marked aria-hidden as it's purely visual. */}
      <div
        aria-hidden
        className="hidden xl:flex absolute inset-x-0 z-0 translate-y-[-62.5%]"
      >
        <FluidGradientText text="Acme" />
      </div>

      {/* Footer bar sits above the gradient (z-10); backdrop-blur with a translucent bg
          where supported, falling back to a solid background otherwise. */}
      <div className="relative z-10 border-t border-border bg-background backdrop-blur-3xl supports-backdrop-filter:bg-background/60">
        <div className="mx-auto max-w-7xl px-6 py-8 md:px-8 md:pb-16 md:pt-12">
          <div className="flex flex-col xl:flex-row gap-8 sm:gap-12">
            <NavLinks sections={footerSections} />
          </div>

          <div className="mt-8 border-t border-border pt-8">
            <div className="flex flex-col items-center gap-4 md:flex-row md:justify-between">
              <p className="text-xs text-muted-foreground">
                &copy; {new Date().getFullYear()} Acme Inc. All rights reserved.
              </p>
              <div className="flex gap-6">
                <Link
                  href="#"
                  className="text-xs text-muted-foreground transition-colors hover:text-foreground"
                >
                  Sitemap
                </Link>
                <Link
                  href="#"
                  className="text-xs text-muted-foreground transition-colors hover:text-foreground"
                >
                  Cookie
                </Link>
              </div>
            </div>
          </div>
        </div>
      </div>
    </footer>
  );
}
```

### `registry/blocks/footer/footer-5/source/components/fluid-gradient-text.tsx`

```tsx
/**
 * Based on Chánh Đại.
 * https://chanhdai.com/components/fluid-gradient-text
 *
 * Original code is licensed under the MIT License.
 * Modified by Hex UI.
 */

"use client"

import { motion, useMotionValue, useSpring, useTransform } from "motion/react"

export type FluidGradientTextProps = {
  /** Text content rendered inside the SVG. */
  text: string
  /**
   * SVG viewBox width used to scale the gradient and text layout.
   * @default 1200
   * */
  svgViewBoxWidth?: number
  /**
   * SVG viewBox height used as the base text size.
   * @default 300
   * */
  svgViewBoxHeight?: number
}

export function FluidGradientText({
  text,
  svgViewBoxWidth = 1200,
  svgViewBoxHeight = 300,
}: FluidGradientTextProps) {
  // Track pointer x as 0..1 across the container, then spring-smooth it into the
  // gradient's start x so the highlight follows the cursor with easing.
  const gradientX1Raw = useMotionValue(0.5)
  const gradientX1 = useSpring(
    useTransform(gradientX1Raw, [0, 1], [0, svgViewBoxWidth]),
    {
      stiffness: 150,
      damping: 25,
    }
  )

  const handleMouseMove = (event: React.MouseEvent<HTMLDivElement>) => {
    const containerRect = event.currentTarget.getBoundingClientRect()
    gradientX1Raw.set(
      (event.clientX - containerRect.left) / containerRect.width
    )
  }

  const handleMouseLeave = () => {
    gradientX1Raw.set(0.5)
  }

  return (
    <div
      className="relative size-full overflow-hidden after:absolute after:bottom-0 after:h-px after:w-full after:bg-current/15"
      onMouseMove={handleMouseMove}
      onMouseLeave={handleMouseLeave}
    >
      <svg
        className="size-full select-none"
        viewBox={`0 0 ${svgViewBoxWidth} ${svgViewBoxHeight}`}
        fill="none"
        xmlns="http://www.w3.org/2000/svg"
      >
        <text
          x="50%"
          y="50%"
          textAnchor="middle"
          dominantBaseline="central"
          stroke="currentColor"
          strokeOpacity="0.1"
          strokeWidth="2"
          fill="url(#fluid_gradient_text_linear)"
          style={{
            fontFamily: "Helvetica",
            fontSize: svgViewBoxHeight,
            fontWeight: "bold",
          }}
        >
          {text}
        </text>
        <defs>
          <motion.linearGradient
            id="fluid_gradient_text_linear"
            x1={gradientX1}
            y1="0"
            x2={svgViewBoxWidth / 2}
            y2={svgViewBoxHeight}
            gradientUnits="userSpaceOnUse"
          >
            {/* Gradient fades from transparent to currentColor, producing the directional wipe. */}
            <stop offset="0.625" stopColor="currentColor" stopOpacity="0" />
            <stop offset="1" stopColor="currentColor" />
          </motion.linearGradient>
        </defs>
      </svg>
    </div>
  )
}
```

### `registry/blocks/footer/footer-5/source/components/nav-links.tsx`

```tsx
import Link from "next/link"

type FooterLinkItem = {
  label: string
  href: string
}

type FooterSection = {
  title: string
  links: FooterLinkItem[]
}

type NavLinksProps = {
  sections: FooterSection[]
}

export function NavLinks({ sections }: NavLinksProps) {
  return (
    <div className="grid gap-6 sm:gap-8 grid-cols-2 xl:w-2/3 xl:flex-1 xl:grid-cols-4">
      {sections.map((section) => (
        <div key={section.title}>
          <h3 className="text-sm font-semibold text-foreground">{section.title}</h3>
          {/* role="list" keeps list semantics; Tailwind preflight strips default list styles. */}
          <ul role="list" className="mt-4 space-y-2 sm:space-y-3">
            {section.links.map((item) => (
              <li key={item.label}>
                <Link
                  href={item.href}
                  className="text-sm text-muted-foreground transition-colors hover:text-foreground"
                >
                  {item.label}
                </Link>
              </li>
            ))}
          </ul>
        </div>
      ))}
    </div>
  )
}
```
