Repository: vercel/next.js
Pull request: doc: useLinkStatus

<!-- Thanks for opening a PR! Your contribution is much appreciated.
To make sure your PR is handled as smoothly as possible we request that you follow the checklist sections below.
Choose the right checklist for the change(s) that you're making:

## For Contributors

### Improving Documentation

- Run `pnpm prettier-fix` to fix formatting issues before opening the PR.
- Read the Docs Contribution Guide to ensure your contribution follows the docs guidelines: https://nextjs.org/docs/community/contribution-guide

### Adding or Updating Examples

- The "examples guidelines" are followed from our contributing doc https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md
- Make sure the linting passes by running `pnpm build && pnpm lint`. See https://github.com/vercel/next.js/blob/canary/contributing/repository/linting.md

### Fixing a bug

- Related issues linked using `fixes #number`
- Tests added. See: https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs
- Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md

### Adding a feature

- Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. (A discussion must be opened, see https://github.com/vercel/next.js/discussions/new?category=ideas)
- Related issues/discussions are linked using `fixes #number`
- e2e tests added (https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs)
- Documentation added
- Telemetry added. In case of a feature if it's used or not.
- Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md


## For Maintainers

- Minimal description (aim for explaining to someone not on the team to understand the PR)
- When linking to a Slack thread, you might want to share details of the conclusion
- Link both the Linear (Fixes NEXT-xxx) and the GitHub issues
- Add review comments if necessary to explain to the reviewer the logic behind a change

### What?

### Why?

### How?

Closes NEXT-
Fixes #

-->


Changed files:
filename: docs/01-app/04-api-reference/04-functions/use-link-status.mdx
patch: @@ -0,0 +1,204 @@
+---
+title: useLinkStatus
+description: API Reference for the useLinkStatus hook.
+---
+
+`useLinkStatus` is a **Client Component** hook that lets you track the loading state of a `Link` component during navigation. It can be used to show loading indicators during page transitions, especially when [prefetching](/docs/app/building-your-application/routing/linking-and-navigating#2-prefetching) is disabled, or the linked route does not have any loading states. 
+
+```tsx filename="app/loading-indicator.tsx" switcher
+'use client'
+
+import { useLinkStatus } from 'next/navigation'
+
+export default function LoadingIndicator() {
+  const { pending } = useLinkStatus()
+  return pending ? <div>Loading...</div> : null
+}
+```
+
+```jsx filename="app/loading-indicator.js" switcher
+'use client'
+
+import { useLinkStatus } from 'next/navigation'
+
+export default function LoadingIndicator() {
+  const { pending } = useLinkStatus()
+  return pending ? <div>Loading...</div> : null
+}
+```
+
+```tsx filename="app/header.tsx" switcher
+import Link from 'next/link'
+import LoadingIndicator from './loading-indicator'
+
+export default function Header() {
+  return (
+    <header>
+      <Link href="/dashboard" prefetch={false}>
+        Dashboard <LoadingIndicator />
+      </Link>
+    </header>
+  )
+}
+```
+
+```jsx filename="app/header.js" switcher
+import Link from 'next/link'
+import LoadingIndicator from './loading-indicator'
+
+export default function Header() {
+  return (
+    <header>
+      <Link href="/dashboard" prefetch={false}>
+        Dashboard <LoadingIndicator />
+      </Link>
+    </header>
+  )
+}
+```
+
+> **Good to know**:
+>
+> - `useLinkStatus` must be used within a descendant component of a `Link` component
+> - The hook is most useful when `prefetch={false}` is set on the `Link` component
+> - If the linked route has been prefetched, the pending state will be skipped
+> - When clicking multiple links in quick succession, only the last link's pending state is shown
+> - This hook is not supported in the Pages Router and will always return `{ pending: false }`
+
+## Parameters
+
+```tsx
+const { pending } = useLinkStatus()
+```
+
+`useLinkStatus` does not take any parameters.
+
+## Returns
+
+`useLinkStatus` returns an object with a single property:
+
+| Property | Type    | Description                                  |
+| -------- | ------- | -------------------------------------------- |
+| pending  | boolean | `true` before history updates, `false` after |
+
+## Examples
+
+### Improving the user experience when navigating with new query parameters
+
+In this example, navigating between categories updates the query string (e.g. ?category=books). However, the page may appear unresponsive because the `<PageSkeleton />` fallback won't replace the existing content (see [preventing unwanted loading indicators](https://react.dev/reference/react/useTransition#preventing-unwanted-loading-indicators)). 
+
+You can use the `useLinkStatus` hook to render a lightweight loading indicator next to the active link and provide immediate feedback to the user while the data is being fetched. 
+
+```tsx filename="app/page.tsx" switcher
+'use client'
+
+import { useSearchParams, useLinkStatus } from 'next/navigation'
+import Link from 'next/link'
+import { Suspense } from 'react'
+
+function LoadingIndicator() {
+  const { pending } = useLinkStatus()
+  return pending ? <span>⌛</span> : null
+}
+
+function MenuBar() {
+  return (
+    <div>
+      <Link href="?category=electronics">
+        Electronics <LoadingIndicator />
+      </Link>
+      <Link href="?category=clothing">
+        Clothing <LoadingIndicator />
+      </Link>
+      <Link href="?category=books">
+        Books <LoadingIndicator />
+      </Link>
+    </div>
+  )
+}
+
+async function ProductList({ category }: { category: string }) {
+  const products = await fetchProducts(category)
+
+  return (
+    <ul>
+      {products.map((product) => (
+        <li key={product}>{product}</li>
+      ))}
+    </ul>
+  )
+}
+
+export default async function ProductCategories({
+  searchParams,
+}: {
+  searchParams: Promise<{
+    category: string
+  }>
+}) {
+  const { category } = await searchParams
+
+  return (
+    <Suspense fallback={<PageSkeleton />}>
+      <MenuBar />
+      <ProductList category={category} />
+    </Suspense>
+  )
+}
+```
+
+```jsx filename="app/page.js" switcher
+'use client'
+
+import { useSearchParams, useLinkStatus } from 'next/navigation'
+import Link from 'next/link'
+import { Suspense } from 'react'
+
+function LoadingIndicator() {
+  const { pending } = useLinkStatus()
+  return pending ? <span>⌛</span> : null
+}
+
+function MenuBar() {
+  return (
+    <div>
+      <Link href="?category=electronics">
+        Electronics <LoadingIndicator />
+      </Link>
+      <Link href="?category=clothing">
+        Clothing <LoadingIndicator />
+      </Link>
+      <Link href="?category=books">
+        Books <LoadingIndicator />
+      </Link>
+    </div>
+  )
+}
+
+async function ProductList({ category }) {
+  const products = await fetchProducts(category)
+
+  return (
+    <ul>
+      {products.map((product) => (
+        <li key={product}>{product}</li>
+      ))}
+    </ul>
+  )
+}
+
+export default async function ProductCategories({ searchParams }) {
+  const { category } = await searchParams
+
+  return (
+    <Suspense fallback={<PageSkeleton />}>
+      <MenuBar />
+      <ProductList category={category} />
+    </Suspense>
+  )
+}
+```
+
+| Version   | Changes                     |
+| --------- | --------------------------- |
+| `v15.3.0` | `useLinkStatus` introduced. |