diff --git a/.changeset/suspense-with-fallback-callback.md b/.changeset/suspense-with-fallback-callback.md
new file mode 100644
index 000000000..b9f534038
--- /dev/null
+++ b/.changeset/suspense-with-fallback-callback.md
@@ -0,0 +1,5 @@
+---
+"@suspensive/react": patch
+---
+
+Support fallback callbacks in `Suspense.with`.
diff --git a/packages/react/src/Suspense.spec.tsx b/packages/react/src/Suspense.spec.tsx
index 282008d0d..c7dcc6114 100644
--- a/packages/react/src/Suspense.spec.tsx
+++ b/packages/react/src/Suspense.spec.tsx
@@ -120,6 +120,25 @@ describe('Suspense.with', () => {
expect(screen.queryByText(FALLBACK)).not.toBeInTheDocument()
})
+ it('should render fallback callback with wrapped component props', async () => {
+ const Wrapped = Suspense.with(
+ {
+ fallback: ({ label }: { label: string }) => <>{label} is loading>,
+ },
+ ({ label }: { label: string }) =>
+ )
+
+ render()
+
+ expect(screen.queryByText(`${TEXT} is loading`)).toBeInTheDocument()
+ expect(screen.queryByText(TEXT)).not.toBeInTheDocument()
+
+ await act(() => vi.advanceTimersByTime(100))
+
+ expect(screen.queryByText(`${TEXT} is loading`)).not.toBeInTheDocument()
+ expect(screen.queryByText(TEXT)).toBeInTheDocument()
+ })
+
it('should use default suspenseProps when {} is provided', () => {
const Component = () =>
{TEXT}
const Wrapped = Suspense.with({}, Component)
diff --git a/packages/react/src/Suspense.tsx b/packages/react/src/Suspense.tsx
index 31fff0ca8..ee9a0d379 100644
--- a/packages/react/src/Suspense.tsx
+++ b/packages/react/src/Suspense.tsx
@@ -1,5 +1,11 @@
'use client'
-import { type ComponentProps, type ComponentType, type SuspenseProps as ReactSuspenseProps, useContext } from 'react'
+import {
+ type ComponentProps,
+ type ComponentType,
+ type ReactNode,
+ type SuspenseProps as ReactSuspenseProps,
+ useContext,
+} from 'react'
import { SuspenseDefaultPropsContext } from './contexts/DefaultPropsContexts'
import type { PropsWithoutChildren } from './utility-types/PropsWithoutChildren'
import { defineSuspense } from './utils/defineSuspense'
@@ -12,6 +18,12 @@ export interface SuspenseProps extends ReactSuspenseProps {
clientOnly?: boolean
}
+type SuspenseWithProps = PropsWithoutChildren<
+ Omit & {
+ fallback?: SuspenseProps['fallback'] | ((props: TProps) => ReactNode)
+ }
+>
+
/**
* This component is just wrapping React's Suspense. to use Suspense easily in Server-side rendering environment like Next.js
* @see {@link https://suspensive.org/docs/react/Suspense Suspensive Docs}
@@ -32,15 +44,19 @@ export const Suspense = Object.assign(
{
displayName: 'Suspense',
with: = Record>(
- suspenseProps: PropsWithoutChildren,
+ suspenseProps: SuspenseWithProps,
Component: ComponentType
) =>
Object.assign(
- (props: TProps) => (
-
-
-
- ),
+ (props: TProps) => {
+ const { fallback, ...restSuspenseProps } = suspenseProps
+
+ return (
+
+
+
+ )
+ },
{ displayName: `${Suspense.displayName}.with(${Component.displayName || Component.name || 'Component'})` }
),
}