diff --git a/.changeset/friendly-dots-join.md b/.changeset/friendly-dots-join.md
new file mode 100644
index 00000000000..5937307a445
--- /dev/null
+++ b/.changeset/friendly-dots-join.md
@@ -0,0 +1,5 @@
+---
+"@clerk/elements": patch
+---
+
+Fix Sign In & Sign Up root fallbacks not rendering as expected
diff --git a/packages/elements/examples/nextjs/app/sign-up/[[...sign-up]]/page.tsx b/packages/elements/examples/nextjs/app/sign-up/[[...sign-up]]/page.tsx
index 950cc211042..aeaf6ca5734 100644
--- a/packages/elements/examples/nextjs/app/sign-up/[[...sign-up]]/page.tsx
+++ b/packages/elements/examples/nextjs/app/sign-up/[[...sign-up]]/page.tsx
@@ -69,14 +69,6 @@ export default function SignUpPage() {
Sign In with Google
-
-
-
- Sign In with Metamask
-
@@ -142,14 +134,6 @@ export default function SignUpPage() {
Sign In with Google
-
-
-
- Sign In with Metamask
-
diff --git a/packages/elements/src/react/common/form/index.tsx b/packages/elements/src/react/common/form/index.tsx
index 9267b11a4b4..796d2bd5db0 100644
--- a/packages/elements/src/react/common/form/index.tsx
+++ b/packages/elements/src/react/common/form/index.tsx
@@ -356,7 +356,8 @@ const useInput = ({
const FORM_NAME = 'ClerkElementsForm';
type FormElement = React.ElementRef;
-type FormProps = SetRequired & {
+type FormProps = Omit & {
+ children: React.ReactNode;
flowActor?: BaseActorRef<{ type: 'SUBMIT' }>;
};
diff --git a/packages/elements/src/react/sign-in/root.tsx b/packages/elements/src/react/sign-in/root.tsx
index 82d860ab2e7..94292b8c54b 100644
--- a/packages/elements/src/react/sign-in/root.tsx
+++ b/packages/elements/src/react/sign-in/root.tsx
@@ -1,5 +1,6 @@
-import { ClerkLoaded, ClerkLoading, useClerk } from '@clerk/clerk-react';
+import { useClerk } from '@clerk/clerk-react';
import { eventComponentMounted } from '@clerk/shared/telemetry';
+import { useSelector } from '@xstate/react';
import React, { useEffect } from 'react';
import { createActor } from 'xstate';
@@ -17,15 +18,21 @@ import { usePathnameWithoutCatchAll } from '../utils/path-inference/next';
type SignInFlowProviderProps = {
children: React.ReactNode;
exampleMode?: boolean;
+ /**
+ * Fallback markup to render while Clerk is loading
+ */
+ fallback?: React.ReactNode;
+ isRootPath: boolean;
};
const actor = createActor(SignInRouterMachine, { inspect });
actor.start();
-function SignInFlowProvider({ children, exampleMode }: SignInFlowProviderProps) {
+function SignInFlowProvider({ children, exampleMode, fallback, isRootPath }: SignInFlowProviderProps) {
const clerk = useClerk();
const router = useClerkRouter();
const formRef = useFormStore();
+ const isReady = useSelector(actor, state => state.value !== 'Idle');
useEffect(() => {
if (!clerk || !router) {
@@ -57,16 +64,17 @@ function SignInFlowProvider({ children, exampleMode }: SignInFlowProviderProps)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [clerk, exampleMode, formRef?.id, !!router]);
+ }, [clerk, exampleMode, formRef?.id, !!router, clerk.loaded]);
- return {children};
+ return (
+
+ {isRootPath && !isReady && fallback ? : null}
+ {clerk.loaded && isReady ? children : null}
+
+ );
}
-export type SignInRootProps = SignInFlowProviderProps & {
- /**
- * Fallback markup to render while Clerk is loading
- */
- fallback?: React.ReactNode;
+export type SignInRootProps = Omit & {
/**
* The base path for your sign-in route.
* Will be automatically inferred in Next.js.
@@ -125,13 +133,12 @@ export function SignInRoot({
router={router}
>
-
- {isRootPath ? (
-
-
-
- ) : null}
- {children}
+
+ {children}
diff --git a/packages/elements/src/react/sign-up/root.tsx b/packages/elements/src/react/sign-up/root.tsx
index 4ce7f86526a..9cea15248d4 100644
--- a/packages/elements/src/react/sign-up/root.tsx
+++ b/packages/elements/src/react/sign-up/root.tsx
@@ -1,4 +1,4 @@
-import { ClerkLoaded, ClerkLoading, useClerk } from '@clerk/clerk-react';
+import { useClerk } from '@clerk/clerk-react';
import { eventComponentMounted } from '@clerk/shared/telemetry';
import { useSelector } from '@xstate/react';
import { useEffect } from 'react';
@@ -18,12 +18,17 @@ import { usePathnameWithoutCatchAll } from '../utils/path-inference/next';
type SignUpFlowProviderProps = {
children: React.ReactNode;
exampleMode?: boolean;
+ /**
+ * Fallback markup to render while Clerk is loading
+ */
+ fallback?: React.ReactNode;
+ isRootPath: boolean;
};
const actor = createActor(SignUpRouterMachine, { inspect });
actor.start();
-function SignUpFlowProvider({ children, exampleMode }: SignUpFlowProviderProps) {
+function SignUpFlowProvider({ children, exampleMode, fallback, isRootPath }: SignUpFlowProviderProps) {
const clerk = useClerk();
const router = useClerkRouter();
const formRef = useFormStore();
@@ -58,16 +63,17 @@ function SignUpFlowProvider({ children, exampleMode }: SignUpFlowProviderProps)
}
});
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [clerk, exampleMode, formRef?.id, !!router]);
+ }, [clerk, exampleMode, formRef?.id, !!router, clerk.loaded]);
- return isReady ? {children} : null;
+ return (
+
+ {isRootPath && !isReady && fallback ? : null}
+ {clerk.loaded && isReady ? children : null}
+
+ );
}
-export type SignUpRootProps = SignUpFlowProviderProps & {
- /**
- * Fallback markup to render while Clerk is loading
- */
- fallback?: React.ReactNode;
+export type SignUpRootProps = Omit & {
/**
* The base path for your sign-up route.
* Will be automatically inferred in Next.js.
@@ -126,13 +132,12 @@ export function SignUpRoot({
router={router}
>
-
- {isRootPath ? (
-
-
-
- ) : null}
- {children}
+
+ {children}