diff --git a/.changeset/sixty-moose-jog.md b/.changeset/sixty-moose-jog.md
new file mode 100644
index 0000000000..d653d62f77
--- /dev/null
+++ b/.changeset/sixty-moose-jog.md
@@ -0,0 +1,5 @@
+---
+'@clerk/clerk-react': minor
+---
+
+Allow ``, `, ``, and `` to render while clerk-js is still loading. This reduces any layout shift that might be caused by these components not rendering immediately.
diff --git a/packages/react/src/components/SignInButton.tsx b/packages/react/src/components/SignInButton.tsx
index 6e33f8ba28..1036cbef43 100644
--- a/packages/react/src/components/SignInButton.tsx
+++ b/packages/react/src/components/SignInButton.tsx
@@ -5,45 +5,48 @@ import type { SignInButtonProps, WithClerkProp } from '../types';
import { assertSingleChild, normalizeWithDefaultValue, safeExecute } from '../utils';
import { withClerk } from './withClerk';
-export const SignInButton = withClerk(({ clerk, children, ...props }: WithClerkProp) => {
- const {
- signUpFallbackRedirectUrl,
- forceRedirectUrl,
- fallbackRedirectUrl,
- signUpForceRedirectUrl,
- mode,
- initialValues,
- ...rest
- } = props;
- children = normalizeWithDefaultValue(children, 'Sign in');
- const child = assertSingleChild(children)('SignInButton');
-
- const clickHandler = () => {
- const opts: SignInProps = {
+export const SignInButton = withClerk(
+ ({ clerk, children, ...props }: WithClerkProp) => {
+ const {
+ signUpFallbackRedirectUrl,
forceRedirectUrl,
fallbackRedirectUrl,
- signUpFallbackRedirectUrl,
signUpForceRedirectUrl,
+ mode,
initialValues,
- };
+ ...rest
+ } = props;
+ children = normalizeWithDefaultValue(children, 'Sign in');
+ const child = assertSingleChild(children)('SignInButton');
- if (mode === 'modal') {
- return clerk.openSignIn(opts);
- }
- return clerk.redirectToSignIn({
- ...opts,
- signInFallbackRedirectUrl: fallbackRedirectUrl,
- signInForceRedirectUrl: forceRedirectUrl,
- });
- };
+ const clickHandler = () => {
+ const opts: SignInProps = {
+ forceRedirectUrl,
+ fallbackRedirectUrl,
+ signUpFallbackRedirectUrl,
+ signUpForceRedirectUrl,
+ initialValues,
+ };
- const wrappedChildClickHandler: React.MouseEventHandler = async e => {
- if (child && typeof child === 'object' && 'props' in child) {
- await safeExecute(child.props.onClick)(e);
- }
- return clickHandler();
- };
+ if (mode === 'modal') {
+ return clerk.openSignIn(opts);
+ }
+ return clerk.redirectToSignIn({
+ ...opts,
+ signInFallbackRedirectUrl: fallbackRedirectUrl,
+ signInForceRedirectUrl: forceRedirectUrl,
+ });
+ };
+
+ const wrappedChildClickHandler: React.MouseEventHandler = async e => {
+ if (child && typeof child === 'object' && 'props' in child) {
+ await safeExecute(child.props.onClick)(e);
+ }
+ return clickHandler();
+ };
- const childProps = { ...rest, onClick: wrappedChildClickHandler };
- return React.cloneElement(child as React.ReactElement, childProps);
-}, 'SignInButton');
+ const childProps = { ...rest, onClick: wrappedChildClickHandler };
+ return React.cloneElement(child as React.ReactElement, childProps);
+ },
+ { component: 'SignInButton', renderWhileLoading: true },
+);
diff --git a/packages/react/src/components/SignInWithMetamaskButton.tsx b/packages/react/src/components/SignInWithMetamaskButton.tsx
index 80148d0635..9776e8d55e 100644
--- a/packages/react/src/components/SignInWithMetamaskButton.tsx
+++ b/packages/react/src/components/SignInWithMetamaskButton.tsx
@@ -28,5 +28,5 @@ export const SignInWithMetamaskButton = withClerk(
const childProps = { ...rest, onClick: wrappedChildClickHandler };
return React.cloneElement(child as React.ReactElement, childProps);
},
- 'SignInWithMetamask',
+ { component: 'SignInWithMetamask', renderWhileLoading: true },
);
diff --git a/packages/react/src/components/SignOutButton.tsx b/packages/react/src/components/SignOutButton.tsx
index 6676684eba..8ff8378906 100644
--- a/packages/react/src/components/SignOutButton.tsx
+++ b/packages/react/src/components/SignOutButton.tsx
@@ -27,5 +27,5 @@ export const SignOutButton = withClerk(
const childProps = { ...rest, onClick: wrappedChildClickHandler };
return React.cloneElement(child as React.ReactElement, childProps);
},
- 'SignOutButton',
+ { component: 'SignOutButton', renderWhileLoading: true },
);
diff --git a/packages/react/src/components/SignUpButton.tsx b/packages/react/src/components/SignUpButton.tsx
index bb8540add1..757439c24d 100644
--- a/packages/react/src/components/SignUpButton.tsx
+++ b/packages/react/src/components/SignUpButton.tsx
@@ -5,49 +5,52 @@ import type { SignUpButtonProps, WithClerkProp } from '../types';
import { assertSingleChild, normalizeWithDefaultValue, safeExecute } from '../utils';
import { withClerk } from './withClerk';
-export const SignUpButton = withClerk(({ clerk, children, ...props }: WithClerkProp) => {
- const {
- fallbackRedirectUrl,
- forceRedirectUrl,
- signInFallbackRedirectUrl,
- signInForceRedirectUrl,
- mode,
- unsafeMetadata,
- initialValues,
- ...rest
- } = props;
-
- children = normalizeWithDefaultValue(children, 'Sign up');
- const child = assertSingleChild(children)('SignUpButton');
-
- const clickHandler = () => {
- const opts: SignUpProps = {
+export const SignUpButton = withClerk(
+ ({ clerk, children, ...props }: WithClerkProp) => {
+ const {
fallbackRedirectUrl,
forceRedirectUrl,
signInFallbackRedirectUrl,
signInForceRedirectUrl,
+ mode,
unsafeMetadata,
initialValues,
+ ...rest
+ } = props;
+
+ children = normalizeWithDefaultValue(children, 'Sign up');
+ const child = assertSingleChild(children)('SignUpButton');
+
+ const clickHandler = () => {
+ const opts: SignUpProps = {
+ fallbackRedirectUrl,
+ forceRedirectUrl,
+ signInFallbackRedirectUrl,
+ signInForceRedirectUrl,
+ unsafeMetadata,
+ initialValues,
+ };
+
+ if (mode === 'modal') {
+ return clerk.openSignUp(opts);
+ }
+
+ return clerk.redirectToSignUp({
+ ...opts,
+ signUpFallbackRedirectUrl: fallbackRedirectUrl,
+ signUpForceRedirectUrl: forceRedirectUrl,
+ });
};
- if (mode === 'modal') {
- return clerk.openSignUp(opts);
- }
-
- return clerk.redirectToSignUp({
- ...opts,
- signUpFallbackRedirectUrl: fallbackRedirectUrl,
- signUpForceRedirectUrl: forceRedirectUrl,
- });
- };
-
- const wrappedChildClickHandler: React.MouseEventHandler = async e => {
- if (child && typeof child === 'object' && 'props' in child) {
- await safeExecute(child.props.onClick)(e);
- }
- return clickHandler();
- };
-
- const childProps = { ...rest, onClick: wrappedChildClickHandler };
- return React.cloneElement(child as React.ReactElement, childProps);
-}, 'SignUpButton');
+ const wrappedChildClickHandler: React.MouseEventHandler = async e => {
+ if (child && typeof child === 'object' && 'props' in child) {
+ await safeExecute(child.props.onClick)(e);
+ }
+ return clickHandler();
+ };
+
+ const childProps = { ...rest, onClick: wrappedChildClickHandler };
+ return React.cloneElement(child as React.ReactElement, childProps);
+ },
+ { component: 'SignUpButton', renderWhileLoading: true },
+);