# Footer 2

> Single-row footer strip with blur stagger on view — logo-cloud-16 footer strip DNA for wordmark, inline links, and copyright.

A shadcn/ui block from the [@nusaiba](https://nusaiba.dev) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/nusaiba/footer-2).

- Page, with a live preview: https://shadcn.exchange/r/nusaiba/footer-2
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/nusaiba/footer-2-light-b6f391ef03a24a54.png
- Registry item: https://nusaiba.dev/r/base-nova/footer-2.json
- Categories: footer
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://nusaiba.dev/r/base-nova/footer-2.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`
- Registry items: `@nusaiba/foundation`

## Files

### `registry/blocks/footer/footer-base-strip.tsx`

```tsx
"use client";

import Link from "next/link";
import { useRef, type PointerEvent } from "react";
import { motion, useInView, useMotionValue, useReducedMotion, useSpring } from "motion/react";
import { motionStagger, motionViewport } from "@/lib/motion-tokens";
import { cn } from "@/lib/utils";

const navLinks = [
	{ href: "/blocks", label: "Blocks" },
	{ href: "/motion", label: "Motion" },
	{ href: "/docs", label: "Docs" },
	{ href: "/pricing", label: "Pricing" },
] as const;

const linkClass = cn(
	"relative inline-flex min-h-10 items-center px-2.5 text-muted-foreground text-xs transition-[color,transform] hover:text-foreground",
	"after:absolute after:top-1/2 after:left-1/2 after:size-10 after:-translate-1/2",
	"active:scale-[0.96]",
);

const magneticSpring = { stiffness: 420, damping: 32, mass: 0.4 };
const maxOffset = 4;

function MagneticLink({
	href,
	label,
	reduceMotion,
	highlight,
}: {
	href: string;
	label: string;
	reduceMotion: boolean;
	highlight?: boolean;
}) {
	const ref = useRef<HTMLDivElement>(null);
	const x = useMotionValue(0);
	const y = useMotionValue(0);
	const springX = useSpring(x, magneticSpring);
	const springY = useSpring(y, magneticSpring);

	function onPointerMove(event: PointerEvent<HTMLDivElement>) {
		if (reduceMotion || !ref.current) return;
		const rect = ref.current.getBoundingClientRect();
		const dx = event.clientX - (rect.left + rect.width / 2);
		const dy = event.clientY - (rect.top + rect.height / 2);
		const influence = Math.max(0, 1 - Math.hypot(dx, dy) / 120);
		x.set(Math.max(-maxOffset, Math.min(maxOffset, dx * influence * 0.08)));
		y.set(Math.max(-maxOffset, Math.min(maxOffset, dy * influence * 0.08)));
	}

	function onPointerLeave() {
		x.set(0);
		y.set(0);
	}

	return (
		<motion.div
			onPointerLeave={onPointerLeave}
			onPointerMove={onPointerMove}
			ref={ref}
			style={reduceMotion ? undefined : { x: springX, y: springY }}
		>
			<Link
				className={cn(
					linkClass,
					highlight && "font-medium text-primary",
				)}
				href={href}
			>
				{label}
			</Link>
		</motion.div>
	);
}

type FooterBaseStripProps = {
	magneticNav?: boolean;
};

export function FooterBaseStrip({ magneticNav = false }: FooterBaseStripProps) {
	const reduceMotion = useReducedMotion();
	const rowRef = useRef<HTMLDivElement>(null);
	const inView = useInView(rowRef, motionViewport);
	const year = new Date().getFullYear();

	const itemVariants = reduceMotion
		? { hidden: { opacity: 1 }, visible: { opacity: 1 } }
		: {
				hidden: { opacity: 0, filter: "blur(4px)", y: 4 },
				visible: { opacity: 1, filter: "blur(0px)", y: 0 },
			};

	return (
		<div className="px-4 py-6 md:py-7">
			<motion.div
				animate={inView ? "visible" : "hidden"}
				className="mx-auto flex w-full max-w-5xl flex-col items-center justify-between gap-4 md:flex-row md:gap-6"
				initial="hidden"
				ref={rowRef}
				variants={{
					hidden: {},
					visible: {
						transition: {
							staggerChildren: motionStagger.item,
							delayChildren: 0.03,
						},
					},
				}}
			>
				<motion.div variants={itemVariants}>
					<Link
						className={cn(
							linkClass,
							"px-0 font-medium text-foreground text-sm tracking-[-0.04em]",
						)}
						href="/"
					>
						Nusaiba
					</Link>
				</motion.div>

				<motion.nav
					aria-label="Footer"
					className="flex flex-wrap items-center justify-center gap-x-0.5 gap-y-0.5"
					variants={itemVariants}
				>
					{navLinks.map((link) =>
						magneticNav ? (
							<MagneticLink
								highlight={link.label === "Pricing"}
								href={link.href}
								key={link.href}
								label={link.label}
								reduceMotion={!!reduceMotion}
							/>
						) : (
							<Link className={linkClass} href={link.href} key={link.href}>
								{link.label}
							</Link>
						),
					)}
				</motion.nav>

				<motion.p
					className="text-muted-foreground text-xs tabular-nums"
					variants={itemVariants}
				>
					© {year} Nusaiba
				</motion.p>
			</motion.div>
		</div>
	);
}
```

### `registry/blocks/footer/2/footer-section.tsx`

```tsx
"use client";

import { FooterBaseStrip } from "../footer-base-strip";

export function FooterStripSection() {
	return (
		<footer className="border-t border-border px-4 py-8 shadow-[0_-1px_0_rgba(0,0,0,0.03)] md:py-12 dark:shadow-[0_-1px_0_rgba(255,255,255,0.04)]">
			<FooterBaseStrip />
		</footer>
	);
}
```
