diff --git a/packages/react-router/src/Matches.tsx b/packages/react-router/src/Matches.tsx
index c75fb19b8e0..1b7ec2cc6bc 100644
--- a/packages/react-router/src/Matches.tsx
+++ b/packages/react-router/src/Matches.tsx
@@ -1,5 +1,6 @@
import * as React from 'react'
import warning from 'tiny-warning'
+import { rootRouteId } from '@tanstack/router-core'
import { CatchBoundary, ErrorComponent } from './CatchBoundary'
import { useRouterState } from './useRouterState'
import { useRouter } from './useRouter'
@@ -12,6 +13,7 @@ import type {
ValidateSelected,
} from './structuralSharing'
import type {
+ AnyRoute,
AnyRouter,
DeepPartial,
Expand,
@@ -41,10 +43,12 @@ declare module '@tanstack/router-core' {
export function Matches() {
const router = useRouter()
+ const rootRoute: AnyRoute = router.routesById[rootRouteId]
- const pendingElement = router.options.defaultPendingComponent ? (
-
- ) : null
+ const PendingComponent =
+ rootRoute.options.pendingComponent ?? router.options.defaultPendingComponent
+
+ const pendingElement = PendingComponent ? : null
// Do not render a root Suspense during SSR or hydrating from SSR
const ResolvedSuspense =
diff --git a/packages/react-router/tests/Matches.test.tsx b/packages/react-router/tests/Matches.test.tsx
index 61fb2461bd7..3cb4f5c2b73 100644
--- a/packages/react-router/tests/Matches.test.tsx
+++ b/packages/react-router/tests/Matches.test.tsx
@@ -121,3 +121,23 @@ test('when filtering useMatches by loaderData', async () => {
expect(await screen.findByText('Incorrect Matches -')).toBeInTheDocument()
})
+
+test('should show pendingComponent of root route', async () => {
+ const root = createRootRoute({
+ pendingComponent: () =>
,
+ loader: async () => {
+ await new Promise((r) => setTimeout(r, 50))
+ },
+ component: () => ,
+ })
+ const router = createRouter({
+ routeTree: root,
+ defaultPendingMs: 0,
+ defaultPendingComponent: () => default pending...
,
+ })
+
+ const rendered = render()
+
+ expect(await rendered.findByTestId('root-pending')).toBeInTheDocument()
+ expect(await rendered.findByTestId('root-content')).toBeInTheDocument()
+})
diff --git a/packages/solid-router/src/Matches.tsx b/packages/solid-router/src/Matches.tsx
index f9fa1d34f7a..52bf981963d 100644
--- a/packages/solid-router/src/Matches.tsx
+++ b/packages/solid-router/src/Matches.tsx
@@ -1,5 +1,6 @@
import * as Solid from 'solid-js'
import warning from 'tiny-warning'
+import { rootRouteId } from '@tanstack/router-core'
import { CatchBoundary, ErrorComponent } from './CatchBoundary'
import { useRouterState } from './useRouterState'
import { useRouter } from './useRouter'
@@ -8,6 +9,7 @@ import { matchContext } from './matchContext'
import { Match } from './Match'
import { SafeFragment } from './SafeFragment'
import type {
+ AnyRoute,
AnyRouter,
DeepPartial,
Expand,
@@ -44,16 +46,17 @@ export function Matches() {
? SafeFragment
: Solid.Suspense
+ const rootRoute: () => AnyRoute = () => router.routesById[rootRouteId]
+ const PendingComponent =
+ rootRoute().options.pendingComponent ??
+ router.options.defaultPendingComponent
+
const OptionalWrapper = router.options.InnerWrap || SafeFragment
return (
- ) : null
- }
+ fallback={PendingComponent ? : null}
>
{!router.isServer && }
diff --git a/packages/solid-router/tests/Matches.test.tsx b/packages/solid-router/tests/Matches.test.tsx
index 6f0f865a1bd..aed930bb0d8 100644
--- a/packages/solid-router/tests/Matches.test.tsx
+++ b/packages/solid-router/tests/Matches.test.tsx
@@ -221,3 +221,24 @@ test('Matches provides InnerWrap context to defaultPendingComponent', async () =
const indexElem = await app.findByText('context-for-default-pending')
expect(indexElem).toBeInTheDocument()
})
+
+test('should show pendingComponent of root route', async () => {
+ const root = createRootRoute({
+ pendingComponent: () => ,
+ loader: async () => {
+ await new Promise((r) => setTimeout(r, 50))
+ },
+ component: () => ,
+ })
+
+ const router = createRouter({
+ routeTree: root,
+ defaultPendingMs: 0,
+ defaultPendingComponent: () => default pending...
,
+ })
+
+ const rendered = render(() => )
+
+ expect(await rendered.findByTestId('root-pending')).toBeInTheDocument()
+ expect(await rendered.findByTestId('root-content')).toBeInTheDocument()
+})