useLinkStatus for Link Pending State
The useLinkStatus hook provides pending state for <Link> navigations. It must be used inside a descendant component of Link.
When to Use
Use useLinkStatus when:
- Prefetching is disabled or in progress
- The destination route is dynamic and doesn't have a
loading.js - You want inline feedback (spinner, shimmer) on the clicked link itself
The Pattern
'use client';
import Link, { useLinkStatus } from 'next/link';
import { Loader2, ArrowUpDown } from 'lucide-react';
function SortIndicator({ icon: Icon, label }: { icon: typeof ArrowUpDown; label: string }) {
const { pending } = useLinkStatus();
return (
<>
{pending ? <Loader2 className="size-4 animate-spin" /> : <Icon className="size-4" />}
<span>{label}</span>
</>
);
}
export function SortButton() {
return (
<Link href="/dashboard?sort=newest" prefetch={false} className="...">
<SortIndicator icon={ArrowUpDown} label="Newest" />
</Link>
);
}Key Points
- Must be a Link descendant -
useLinkStatusonly works inside a component rendered within<Link> - Use
prefetch={false}- If the route is prefetched, pending state is skipped - Extract to child component - The hook tracks the parent Link's navigation state
- Style as Link - Use
buttonVariantsfrom shadcn/ui to style Links as buttons
vs useTransition + router.push
| Approach | Pros | Cons |
|----------|------|------|
| useLinkStatus | Simpler, no state management, declarative | Must use <Link>, no optimistic updates |
| useTransition + router.push | Full control, optimistic updates possible | More boilerplate, imperative |
Choose useLinkStatus for simple navigation feedback. Use useTransition when you need optimistic state updates during navigation.