diff --git a/eslint.config.ts b/eslint.config.ts
index cdbc5aa62..844817204 100644
--- a/eslint.config.ts
+++ b/eslint.config.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
/* eslint-disable @typescript-eslint/no-explicit-any */
import js from "@eslint/js";
diff --git a/packages/angular/jest.config.ts b/packages/angular/jest.config.ts
index 5b1d8abf3..d6d1aff08 100644
--- a/packages/angular/jest.config.ts
+++ b/packages/angular/jest.config.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import type { Config } from "jest";
import { createCjsPreset } from "jest-preset-angular/presets/index.js";
diff --git a/packages/angular/src/lib/auth/forms/email-link-auth-form.ts b/packages/angular/src/lib/auth/forms/email-link-auth-form.ts
index 8be54e5c9..223297376 100644
--- a/packages/angular/src/lib/auth/forms/email-link-auth-form.ts
+++ b/packages/angular/src/lib/auth/forms/email-link-auth-form.ts
@@ -64,6 +64,12 @@ import { injectEmailLinkAuthFormSchema, injectTranslation, injectUI } from "../.
}
`,
})
+/**
+ * A form component for email link authentication.
+ *
+ * Sends a sign-in link to the user's email address and automatically completes sign-in
+ * if the user arrives via an email link.
+ */
export class EmailLinkAuthFormComponent {
private ui = injectUI();
private formSchema = injectEmailLinkAuthFormSchema();
@@ -75,7 +81,9 @@ export class EmailLinkAuthFormComponent {
emailSentMessage = injectTranslation("messages", "signInLinkSent");
unknownErrorLabel = injectTranslation("errors", "unknownError");
+ /** Event emitter fired when sign-in link email is sent. */
@Output() emailSent = new EventEmitter();
+ /** Event emitter for successful sign-in. */
@Output() signIn = new EventEmitter();
form = injectForm({
diff --git a/packages/angular/src/lib/auth/forms/forgot-password-auth-form.ts b/packages/angular/src/lib/auth/forms/forgot-password-auth-form.ts
index fa72689eb..40a190f13 100644
--- a/packages/angular/src/lib/auth/forms/forgot-password-auth-form.ts
+++ b/packages/angular/src/lib/auth/forms/forgot-password-auth-form.ts
@@ -73,6 +73,11 @@ import { injectForgotPasswordAuthFormSchema, injectTranslation, injectUI } from
}
`,
})
+/**
+ * A form component for requesting a password reset email.
+ *
+ * Displays a success message after the email is sent.
+ */
export class ForgotPasswordAuthFormComponent {
private ui = injectUI();
private formSchema = injectForgotPasswordAuthFormSchema();
@@ -85,8 +90,10 @@ export class ForgotPasswordAuthFormComponent {
checkEmailForResetMessage = injectTranslation("messages", "checkEmailForReset");
unknownErrorLabel = injectTranslation("errors", "unknownError");
+ /** Event emitter for back to sign in action. */
backToSignIn = input>();
+ /** Event emitter fired when password reset email is sent. */
@Output() passwordSent = new EventEmitter();
form = injectForm({
diff --git a/packages/angular/src/lib/auth/forms/mfa/sms-multi-factor-assertion-form.ts b/packages/angular/src/lib/auth/forms/mfa/sms-multi-factor-assertion-form.ts
index 353b816c7..b45742577 100644
--- a/packages/angular/src/lib/auth/forms/mfa/sms-multi-factor-assertion-form.ts
+++ b/packages/angular/src/lib/auth/forms/mfa/sms-multi-factor-assertion-form.ts
@@ -63,10 +63,15 @@ type PhoneMultiFactorInfo = MultiFactorInfo & {
`,
})
+/**
+ * A form component for requesting SMS verification code during MFA assertion.
+ */
export class SmsMultiFactorAssertionPhoneFormComponent {
private ui = injectUI();
+ /** The multi-factor info hint containing phone number details. */
hint = input.required();
+ /** Event emitter fired when verification ID is received. */
@Output() onSubmit = new EventEmitter();
sendCodeLabel = injectTranslation("labels", "sendCode");
@@ -164,11 +169,16 @@ export class SmsMultiFactorAssertionPhoneFormComponent {
`,
})
+/**
+ * A form component for verifying SMS code during MFA assertion.
+ */
export class SmsMultiFactorAssertionVerifyFormComponent {
private ui = injectUI();
private formSchema = injectMultiFactorPhoneAuthVerifyFormSchema();
+ /** The verification ID received from the phone form. */
verificationId = input.required();
+ /** Event emitter for successful MFA assertion. */
@Output() onSuccess = new EventEmitter();
verificationCodeLabel = injectTranslation("labels", "verificationCode");
@@ -238,8 +248,15 @@ export class SmsMultiFactorAssertionVerifyFormComponent {
`,
})
+/**
+ * A form component for SMS multi-factor authentication assertion.
+ *
+ * Manages the flow between requesting and verifying SMS codes for MFA.
+ */
export class SmsMultiFactorAssertionFormComponent {
+ /** The multi-factor info hint containing phone number details. */
hint = input.required();
+ /** Event emitter for successful MFA assertion. */
@Output() onSuccess = new EventEmitter();
verification = signal<{ verificationId: string } | null>(null);
diff --git a/packages/angular/src/lib/auth/forms/mfa/sms-multi-factor-enrollment-form.ts b/packages/angular/src/lib/auth/forms/mfa/sms-multi-factor-enrollment-form.ts
index 7f65985ce..6a949b6d0 100644
--- a/packages/angular/src/lib/auth/forms/mfa/sms-multi-factor-enrollment-form.ts
+++ b/packages/angular/src/lib/auth/forms/mfa/sms-multi-factor-enrollment-form.ts
@@ -111,6 +111,11 @@ import {
`,
})
+/**
+ * A form component for SMS multi-factor authentication enrollment.
+ *
+ * Manages the flow between phone number entry and verification code entry for MFA enrollment.
+ */
export class SmsMultiFactorEnrollmentFormComponent {
private ui = injectUI();
private phoneFormSchema = injectMultiFactorPhoneAuthNumberFormSchema();
@@ -128,6 +133,7 @@ export class SmsMultiFactorEnrollmentFormComponent {
verifyCodeLabel = injectTranslation("labels", "verifyCode");
smsVerificationPrompt = injectTranslation("prompts", "smsVerificationPrompt");
+ /** Event emitter fired when MFA enrollment is completed. */
@Output() onEnrollment = new EventEmitter();
recaptchaContainer = viewChild.required>("recaptchaContainer");
diff --git a/packages/angular/src/lib/auth/forms/mfa/totp-multi-factor-assertion-form.ts b/packages/angular/src/lib/auth/forms/mfa/totp-multi-factor-assertion-form.ts
index 4471e66da..ecf9190c6 100644
--- a/packages/angular/src/lib/auth/forms/mfa/totp-multi-factor-assertion-form.ts
+++ b/packages/angular/src/lib/auth/forms/mfa/totp-multi-factor-assertion-form.ts
@@ -58,11 +58,18 @@ import { TotpMultiFactorGenerator, type MultiFactorInfo, type UserCredential } f
`,
})
+/**
+ * A form component for TOTP multi-factor authentication assertion.
+ *
+ * Allows users to enter a TOTP code from their authenticator app.
+ */
export class TotpMultiFactorAssertionFormComponent {
private ui = injectUI();
private formSchema = injectMultiFactorTotpAuthVerifyFormSchema();
+ /** The multi-factor info hint containing TOTP details. */
hint = input.required();
+ /** Event emitter for successful MFA assertion. */
@Output() onSuccess = new EventEmitter();
verificationCodeLabel = injectTranslation("labels", "verificationCode");
diff --git a/packages/angular/src/lib/auth/forms/mfa/totp-multi-factor-enrollment-form.ts b/packages/angular/src/lib/auth/forms/mfa/totp-multi-factor-enrollment-form.ts
index e96732791..157dde79f 100644
--- a/packages/angular/src/lib/auth/forms/mfa/totp-multi-factor-enrollment-form.ts
+++ b/packages/angular/src/lib/auth/forms/mfa/totp-multi-factor-enrollment-form.ts
@@ -66,10 +66,14 @@ import {
`,
})
+/**
+ * A form component for generating a TOTP secret and display name during MFA enrollment.
+ */
export class TotpMultiFactorSecretGenerationFormComponent {
private ui = injectUI();
private formSchema = injectMultiFactorTotpAuthNumberFormSchema();
+ /** Event emitter fired when TOTP secret is generated. */
@Output() onSubmit = new EventEmitter<{ secret: TotpSecret; displayName: string }>();
displayNameLabel = injectTranslation("labels", "displayName");
@@ -150,12 +154,20 @@ export class TotpMultiFactorSecretGenerationFormComponent {
`,
})
+/**
+ * A form component for verifying TOTP code during MFA enrollment.
+ *
+ * Displays a QR code and allows users to verify their authenticator app setup.
+ */
export class TotpMultiFactorVerificationFormComponent {
private ui = injectUI();
private formSchema = injectMultiFactorTotpAuthVerifyFormSchema();
+ /** The TOTP secret generated in the previous step. */
secret = input.required();
+ /** The display name for the TOTP factor. */
displayName = input.required();
+ /** Event emitter fired when MFA enrollment is completed. */
@Output() onEnrollment = new EventEmitter();
verificationCodeLabel = injectTranslation("labels", "verificationCode");
@@ -224,10 +236,16 @@ export class TotpMultiFactorVerificationFormComponent {
`,
})
+/**
+ * A form component for TOTP multi-factor authentication enrollment.
+ *
+ * Manages the flow between secret generation and verification for TOTP MFA enrollment.
+ */
export class TotpMultiFactorEnrollmentFormComponent {
private ui = injectUI();
enrollment = signal<{ secret: TotpSecret; displayName: string } | null>(null);
+ /** Event emitter fired when MFA enrollment is completed. */
@Output() onEnrollment = new EventEmitter();
constructor() {
diff --git a/packages/angular/src/lib/auth/forms/multi-factor-auth-assertion-form.ts b/packages/angular/src/lib/auth/forms/multi-factor-auth-assertion-form.ts
index 55fcc1b33..b078d2a8e 100644
--- a/packages/angular/src/lib/auth/forms/multi-factor-auth-assertion-form.ts
+++ b/packages/angular/src/lib/auth/forms/multi-factor-auth-assertion-form.ts
@@ -59,6 +59,11 @@ import { ButtonComponent } from "../../components/button";
`,
})
+/**
+ * A form component for multi-factor authentication assertion.
+ *
+ * Allows users to select and complete MFA verification using SMS or TOTP.
+ */
export class MultiFactorAuthAssertionFormComponent {
private ui = injectUI();
@@ -71,6 +76,7 @@ export class MultiFactorAuthAssertionFormComponent {
});
}
+ /** Event emitter for successful MFA assertion. */
@Output() onSuccess = new EventEmitter();
resolver = computed(() => {
diff --git a/packages/angular/src/lib/auth/forms/multi-factor-auth-enrollment-form.ts b/packages/angular/src/lib/auth/forms/multi-factor-auth-enrollment-form.ts
index 30ee40402..559fae251 100644
--- a/packages/angular/src/lib/auth/forms/multi-factor-auth-enrollment-form.ts
+++ b/packages/angular/src/lib/auth/forms/multi-factor-auth-enrollment-form.ts
@@ -60,8 +60,15 @@ type Hint = (typeof FactorId)[keyof typeof FactorId];
`,
})
+/**
+ * A form component for multi-factor authentication enrollment.
+ *
+ * Allows users to enroll in MFA using SMS or TOTP methods.
+ */
export class MultiFactorAuthEnrollmentFormComponent implements OnInit {
+ /** The available MFA factor types for enrollment. */
hints = input([FactorId.TOTP, FactorId.PHONE]);
+ /** Event emitter fired when MFA enrollment is completed. */
@Output() onEnrollment = new EventEmitter();
selectedHint = signal(undefined);
diff --git a/packages/angular/src/lib/auth/forms/phone-auth-form.ts b/packages/angular/src/lib/auth/forms/phone-auth-form.ts
index acd988c2c..39c6a77b8 100644
--- a/packages/angular/src/lib/auth/forms/phone-auth-form.ts
+++ b/packages/angular/src/lib/auth/forms/phone-auth-form.ts
@@ -79,11 +79,16 @@ import {
`,
})
+/**
+ * A form component for entering a phone number and requesting a verification code.
+ */
export class PhoneNumberFormComponent {
private ui = injectUI();
private formSchema = injectPhoneAuthFormSchema();
+ /** Event emitter fired when phone number is verified and verification ID is received. */
@Output() onSubmit = new EventEmitter<{ verificationId: string; phoneNumber: string }>();
+ /** The selected country code for phone number formatting. */
country = signal(countryData[0].code);
phoneNumberLabel = injectTranslation("labels", "phoneNumber");
@@ -187,11 +192,16 @@ export class PhoneNumberFormComponent {
`,
})
+/**
+ * A form component for entering and verifying the SMS verification code.
+ */
export class VerificationFormComponent {
private ui = injectUI();
private formSchema = injectPhoneAuthVerifyFormSchema();
+ /** The verification ID received from the phone number form. */
verificationId = input.required();
+ /** Event emitter for successful sign-in. */
@Output() signIn = new EventEmitter();
verificationCodeLabel = injectTranslation("labels", "verificationCode");
@@ -259,8 +269,14 @@ export class VerificationFormComponent {
`,
})
+/**
+ * A form component for phone number authentication.
+ *
+ * Manages the flow between phone number entry and verification code entry.
+ */
export class PhoneAuthFormComponent {
verificationId = signal(null);
+ /** Event emitter for successful sign-in. */
@Output() signIn = new EventEmitter();
handlePhoneSubmit(data: { verificationId: string; phoneNumber: string }) {
diff --git a/packages/angular/src/lib/auth/forms/sign-in-auth-form.ts b/packages/angular/src/lib/auth/forms/sign-in-auth-form.ts
index 94ba33aaa..a88cb3379 100644
--- a/packages/angular/src/lib/auth/forms/sign-in-auth-form.ts
+++ b/packages/angular/src/lib/auth/forms/sign-in-auth-form.ts
@@ -87,6 +87,9 @@ import {
`,
})
+/**
+ * A form component for signing in with email and password.
+ */
export class SignInAuthFormComponent {
private ui = injectUI();
private formSchema = injectSignInAuthFormSchema();
@@ -99,9 +102,12 @@ export class SignInAuthFormComponent {
signUpLabel = injectTranslation("labels", "signUp");
unknownErrorLabel = injectTranslation("errors", "unknownError");
+ /** Event emitter for forgot password action. */
forgotPassword = input>();
+ /** Event emitter for sign up action. */
signUp = input>();
+ /** Event emitter for successful sign-in. */
@Output() signIn = new EventEmitter();
form = injectForm({
diff --git a/packages/angular/src/lib/auth/forms/sign-up-auth-form.ts b/packages/angular/src/lib/auth/forms/sign-up-auth-form.ts
index 5c3a9d35a..266d2904d 100644
--- a/packages/angular/src/lib/auth/forms/sign-up-auth-form.ts
+++ b/packages/angular/src/lib/auth/forms/sign-up-auth-form.ts
@@ -78,6 +78,11 @@ import {
`,
})
+/**
+ * A form component for signing up with email and password.
+ *
+ * Optionally includes a display name field if the requireDisplayName behavior is enabled.
+ */
export class SignUpAuthFormComponent {
private ui = injectUI();
private formSchema = injectSignUpAuthFormSchema();
@@ -94,8 +99,10 @@ export class SignUpAuthFormComponent {
signInLabel = injectTranslation("labels", "signIn");
unknownErrorLabel = injectTranslation("errors", "unknownError");
+ /** Event emitter for sign in action. */
signIn = input>();
+ /** Event emitter for successful sign-up. */
@Output() signUp = new EventEmitter();
form = injectForm({
diff --git a/packages/angular/src/lib/auth/oauth/apple-sign-in-button.ts b/packages/angular/src/lib/auth/oauth/apple-sign-in-button.ts
index 8d760d5cf..bdc9e81f0 100644
--- a/packages/angular/src/lib/auth/oauth/apple-sign-in-button.ts
+++ b/packages/angular/src/lib/auth/oauth/apple-sign-in-button.ts
@@ -35,14 +35,20 @@ import { AppleLogoComponent } from "../../components/logos/apple";
`,
})
+/**
+ * A button component for signing in with Apple.
+ */
export class AppleSignInButtonComponent {
ui = injectUI();
signInWithAppleLabel = injectTranslation("labels", "signInWithApple");
+ /** Whether to use themed styling. */
themed = input(false);
+ /** Event emitter for successful sign-in. */
signIn = output();
private defaultProvider = new OAuthProvider("apple.com");
+ /** Optional custom OAuth provider configuration. */
provider = input();
get appleProvider() {
diff --git a/packages/angular/src/lib/auth/oauth/facebook-sign-in-button.ts b/packages/angular/src/lib/auth/oauth/facebook-sign-in-button.ts
index 9d65c8030..6c2ed949e 100644
--- a/packages/angular/src/lib/auth/oauth/facebook-sign-in-button.ts
+++ b/packages/angular/src/lib/auth/oauth/facebook-sign-in-button.ts
@@ -35,14 +35,20 @@ import { FacebookLogoComponent } from "../../components/logos/facebook";
`,
})
+/**
+ * A button component for signing in with Facebook.
+ */
export class FacebookSignInButtonComponent {
ui = injectUI();
signInWithFacebookLabel = injectTranslation("labels", "signInWithFacebook");
+ /** Whether to use themed styling. */
themed = input(false);
+ /** Event emitter for successful sign-in. */
signIn = output();
private defaultProvider = new FacebookAuthProvider();
+ /** Optional custom OAuth provider configuration. */
provider = input();
get facebookProvider() {
diff --git a/packages/angular/src/lib/auth/oauth/github-sign-in-button.ts b/packages/angular/src/lib/auth/oauth/github-sign-in-button.ts
index 049d6f54e..3e41e82ed 100644
--- a/packages/angular/src/lib/auth/oauth/github-sign-in-button.ts
+++ b/packages/angular/src/lib/auth/oauth/github-sign-in-button.ts
@@ -35,13 +35,19 @@ import { GithubLogoComponent } from "../../components/logos/github";
`,
})
+/**
+ * A button component for signing in with GitHub.
+ */
export class GitHubSignInButtonComponent {
signInWithGitHubLabel = injectTranslation("labels", "signInWithGitHub");
+ /** Whether to use themed styling. */
themed = input(false);
+ /** Event emitter for successful sign-in. */
signIn = output();
private defaultProvider = new GithubAuthProvider();
+ /** Optional custom OAuth provider configuration. */
provider = input();
get githubProvider() {
diff --git a/packages/angular/src/lib/auth/oauth/google-sign-in-button.ts b/packages/angular/src/lib/auth/oauth/google-sign-in-button.ts
index 3875734e2..11119857e 100644
--- a/packages/angular/src/lib/auth/oauth/google-sign-in-button.ts
+++ b/packages/angular/src/lib/auth/oauth/google-sign-in-button.ts
@@ -35,14 +35,20 @@ import { GoogleLogoComponent } from "../../components/logos/google";
`,
})
+/**
+ * A button component for signing in with Google.
+ */
export class GoogleSignInButtonComponent {
ui = injectUI();
signInWithGoogleLabel = injectTranslation("labels", "signInWithGoogle");
+ /** Whether to use themed styling. */
themed = input(false);
+ /** Event emitter for successful sign-in. */
signIn = output();
private defaultProvider = new GoogleAuthProvider();
+ /** Optional custom OAuth provider configuration. */
provider = input();
get googleProvider() {
diff --git a/packages/angular/src/lib/auth/oauth/microsoft-sign-in-button.ts b/packages/angular/src/lib/auth/oauth/microsoft-sign-in-button.ts
index 5472aeca8..d292fcfc9 100644
--- a/packages/angular/src/lib/auth/oauth/microsoft-sign-in-button.ts
+++ b/packages/angular/src/lib/auth/oauth/microsoft-sign-in-button.ts
@@ -35,13 +35,19 @@ import { MicrosoftLogoComponent } from "../../components/logos/microsoft";
`,
})
+/**
+ * A button component for signing in with Microsoft.
+ */
export class MicrosoftSignInButtonComponent {
signInWithMicrosoftLabel = injectTranslation("labels", "signInWithMicrosoft");
+ /** Whether to use themed styling. */
themed = input(false);
+ /** Event emitter for successful sign-in. */
signIn = output();
private defaultProvider = new OAuthProvider("microsoft.com");
+ /** Optional custom OAuth provider configuration. */
provider = input();
get microsoftProvider() {
diff --git a/packages/angular/src/lib/auth/oauth/oauth-button.ts b/packages/angular/src/lib/auth/oauth/oauth-button.ts
index e0308bc2d..1556808e7 100644
--- a/packages/angular/src/lib/auth/oauth/oauth-button.ts
+++ b/packages/angular/src/lib/auth/oauth/oauth-button.ts
@@ -49,11 +49,17 @@ import { FirebaseUIError, signInWithProvider, getTranslation } from "@invertase/
`,
})
+/**
+ * A generic OAuth button component for signing in with any OAuth provider.
+ */
export class OAuthButtonComponent {
ui = injectUI();
+ /** The OAuth provider to use for sign-in. */
provider = input.required();
+ /** Whether to use themed styling. */
themed = input();
error = signal(null);
+ /** Event emitter for successful sign-in. */
signIn = output();
buttonVariant = computed(() => {
diff --git a/packages/angular/src/lib/auth/oauth/twitter-sign-in-button.ts b/packages/angular/src/lib/auth/oauth/twitter-sign-in-button.ts
index 56b8471ff..cba57a801 100644
--- a/packages/angular/src/lib/auth/oauth/twitter-sign-in-button.ts
+++ b/packages/angular/src/lib/auth/oauth/twitter-sign-in-button.ts
@@ -35,13 +35,19 @@ import { TwitterLogoComponent } from "../../components/logos/twitter";
`,
})
+/**
+ * A button component for signing in with Twitter/X.
+ */
export class TwitterSignInButtonComponent {
signInWithTwitterLabel = injectTranslation("labels", "signInWithTwitter");
+ /** Whether to use themed styling. */
themed = input(false);
+ /** Event emitter for successful sign-in. */
signIn = output();
private defaultProvider = new TwitterAuthProvider();
+ /** Optional custom OAuth provider configuration. */
provider = input();
get twitterProvider() {
diff --git a/packages/angular/src/lib/auth/screens/email-link-auth-screen.ts b/packages/angular/src/lib/auth/screens/email-link-auth-screen.ts
index f0a744659..eaf33575f 100644
--- a/packages/angular/src/lib/auth/screens/email-link-auth-screen.ts
+++ b/packages/angular/src/lib/auth/screens/email-link-auth-screen.ts
@@ -66,6 +66,11 @@ import { User } from "@angular/fire/auth";
}
`,
})
+/**
+ * A screen component for email link authentication.
+ *
+ * Automatically displays the MFA assertion screen if a multi-factor resolver is present.
+ */
export class EmailLinkAuthScreenComponent {
private ui = injectUI();
@@ -80,6 +85,8 @@ export class EmailLinkAuthScreenComponent {
});
}
+ /** Event emitter fired when sign-in link email is sent. */
@Output() emailSent = new EventEmitter();
+ /** Event emitter for successful sign-in. */
@Output() signIn = new EventEmitter();
}
diff --git a/packages/angular/src/lib/auth/screens/forgot-password-auth-screen.ts b/packages/angular/src/lib/auth/screens/forgot-password-auth-screen.ts
index 93248d871..ed17b083e 100644
--- a/packages/angular/src/lib/auth/screens/forgot-password-auth-screen.ts
+++ b/packages/angular/src/lib/auth/screens/forgot-password-auth-screen.ts
@@ -55,10 +55,15 @@ import { ForgotPasswordAuthFormComponent } from "../forms/forgot-password-auth-f
`,
})
+/**
+ * A screen component for requesting a password reset.
+ */
export class ForgotPasswordAuthScreenComponent {
titleText = injectTranslation("labels", "resetPassword");
subtitleText = injectTranslation("prompts", "enterEmailToReset");
+ /** Event emitter fired when password reset email is sent. */
@Output() passwordSent = new EventEmitter();
+ /** Event emitter for back to sign in action. */
@Output() backToSignIn = new EventEmitter();
}
diff --git a/packages/angular/src/lib/auth/screens/multi-factor-auth-assertion-screen.ts b/packages/angular/src/lib/auth/screens/multi-factor-auth-assertion-screen.ts
index 038244804..2a66aed1e 100644
--- a/packages/angular/src/lib/auth/screens/multi-factor-auth-assertion-screen.ts
+++ b/packages/angular/src/lib/auth/screens/multi-factor-auth-assertion-screen.ts
@@ -56,7 +56,13 @@ import {
`,
})
+/**
+ * A screen component for multi-factor authentication assertion.
+ *
+ * Displays the MFA assertion form for completing multi-factor verification.
+ */
export class MultiFactorAuthAssertionScreenComponent {
+ /** Event emitter for successful MFA assertion. */
@Output() onSuccess = new EventEmitter();
titleText = injectTranslation("labels", "multiFactorAssertion");
diff --git a/packages/angular/src/lib/auth/screens/multi-factor-auth-enrollment-screen.ts b/packages/angular/src/lib/auth/screens/multi-factor-auth-enrollment-screen.ts
index 69faaac2a..f759d66b5 100644
--- a/packages/angular/src/lib/auth/screens/multi-factor-auth-enrollment-screen.ts
+++ b/packages/angular/src/lib/auth/screens/multi-factor-auth-enrollment-screen.ts
@@ -58,8 +58,15 @@ type Hint = (typeof FactorId)[keyof typeof FactorId];
`,
})
+/**
+ * A screen component for multi-factor authentication enrollment.
+ *
+ * Displays the MFA enrollment form for setting up multi-factor authentication.
+ */
export class MultiFactorAuthEnrollmentScreenComponent {
+ /** The available MFA factor types for enrollment. */
hints = input([FactorId.TOTP, FactorId.PHONE]);
+ /** Event emitter fired when MFA enrollment is completed. */
@Output() onEnrollment = new EventEmitter();
titleText = injectTranslation("labels", "multiFactorEnrollment");
diff --git a/packages/angular/src/lib/auth/screens/oauth-screen.ts b/packages/angular/src/lib/auth/screens/oauth-screen.ts
index 3fa0a9808..d12851600 100644
--- a/packages/angular/src/lib/auth/screens/oauth-screen.ts
+++ b/packages/angular/src/lib/auth/screens/oauth-screen.ts
@@ -68,6 +68,12 @@ import { type User } from "@angular/fire/auth";
}
`,
})
+/**
+ * A screen component for OAuth authentication.
+ *
+ * Automatically displays the MFA assertion screen if a multi-factor resolver is present.
+ * Use this screen to display OAuth sign-in buttons.
+ */
export class OAuthScreenComponent {
private ui = injectUI();
@@ -82,5 +88,6 @@ export class OAuthScreenComponent {
});
}
+ /** Event emitter for successful sign-in. */
@Output() onSignIn = new EventEmitter();
}
diff --git a/packages/angular/src/lib/auth/screens/phone-auth-screen.ts b/packages/angular/src/lib/auth/screens/phone-auth-screen.ts
index 96a5bde86..392666aac 100644
--- a/packages/angular/src/lib/auth/screens/phone-auth-screen.ts
+++ b/packages/angular/src/lib/auth/screens/phone-auth-screen.ts
@@ -66,6 +66,11 @@ import { User } from "@angular/fire/auth";
}
`,
})
+/**
+ * A screen component for phone number authentication.
+ *
+ * Automatically displays the MFA assertion screen if a multi-factor resolver is present.
+ */
export class PhoneAuthScreenComponent {
private ui = injectUI();
@@ -80,5 +85,6 @@ export class PhoneAuthScreenComponent {
});
}
+ /** Event emitter for successful sign-in. */
@Output() signIn = new EventEmitter();
}
diff --git a/packages/angular/src/lib/auth/screens/sign-in-auth-screen.ts b/packages/angular/src/lib/auth/screens/sign-in-auth-screen.ts
index 14b0dc36d..86cba026b 100644
--- a/packages/angular/src/lib/auth/screens/sign-in-auth-screen.ts
+++ b/packages/angular/src/lib/auth/screens/sign-in-auth-screen.ts
@@ -66,6 +66,11 @@ import { Auth, authState, User, UserCredential } from "@angular/fire/auth";
}
`,
})
+/**
+ * A screen component for email/password sign-in.
+ *
+ * Automatically displays the MFA assertion screen if a multi-factor resolver is present.
+ */
export class SignInAuthScreenComponent {
private ui = injectUI();
@@ -79,7 +84,10 @@ export class SignInAuthScreenComponent {
});
}
+ /** Event emitter for forgot password action. */
@Output() forgotPassword = new EventEmitter();
+ /** Event emitter for sign up action. */
@Output() signUp = new EventEmitter();
+ /** Event emitter for successful sign-in. */
@Output() signIn = new EventEmitter();
}
diff --git a/packages/angular/src/lib/auth/screens/sign-up-auth-screen.ts b/packages/angular/src/lib/auth/screens/sign-up-auth-screen.ts
index f479917a1..9ceaaab22 100644
--- a/packages/angular/src/lib/auth/screens/sign-up-auth-screen.ts
+++ b/packages/angular/src/lib/auth/screens/sign-up-auth-screen.ts
@@ -67,6 +67,11 @@ import {
}
`,
})
+/**
+ * A screen component for email/password sign-up.
+ *
+ * Automatically displays the MFA assertion screen if a multi-factor resolver is present.
+ */
export class SignUpAuthScreenComponent {
private ui = injectUI();
@@ -81,6 +86,8 @@ export class SignUpAuthScreenComponent {
});
}
+ /** Event emitter for successful sign-up. */
@Output() signUp = new EventEmitter();
+ /** Event emitter for sign in action. */
@Output() signIn = new EventEmitter();
}
diff --git a/packages/angular/src/lib/components/button.ts b/packages/angular/src/lib/components/button.ts
index dd73008c7..70654bcfd 100644
--- a/packages/angular/src/lib/components/button.ts
+++ b/packages/angular/src/lib/components/button.ts
@@ -22,7 +22,11 @@ import { buttonVariant, type ButtonVariant } from "@invertase/firebaseui-styles"
template: ``,
standalone: true,
})
+/**
+ * A customizable button component with multiple variants.
+ */
export class ButtonComponent {
+ /** The visual variant of the button. */
variant = input();
@HostBinding("class")
diff --git a/packages/angular/src/lib/components/card.ts b/packages/angular/src/lib/components/card.ts
index 48fe36cac..02aa8bba9 100644
--- a/packages/angular/src/lib/components/card.ts
+++ b/packages/angular/src/lib/components/card.ts
@@ -30,6 +30,9 @@ import { CommonModule } from "@angular/common";
`,
})
+/**
+ * A card container component for grouping related content.
+ */
export class CardComponent {}
@Component({
@@ -45,6 +48,9 @@ export class CardComponent {}
`,
})
+/**
+ * The header section of a card.
+ */
export class CardHeaderComponent {}
@Component({
@@ -61,6 +67,9 @@ export class CardHeaderComponent {}
`,
})
+/**
+ * The title of a card.
+ */
export class CardTitleComponent {}
@Component({
@@ -77,6 +86,9 @@ export class CardTitleComponent {}
`,
})
+/**
+ * The subtitle of a card.
+ */
export class CardSubtitleComponent {}
@Component({
@@ -89,4 +101,7 @@ export class CardSubtitleComponent {}
},
template: ` `,
})
+/**
+ * The content section of a card.
+ */
export class CardContentComponent {}
diff --git a/packages/angular/src/lib/components/content.ts b/packages/angular/src/lib/components/content.ts
index ce3ddc4b9..b426dea79 100644
--- a/packages/angular/src/lib/components/content.ts
+++ b/packages/angular/src/lib/components/content.ts
@@ -32,6 +32,9 @@ import { injectTranslation } from "../provider";
`,
})
+/**
+ * A content wrapper component that displays a divider and children content.
+ */
export class ContentComponent {
dividerOrLabel = injectTranslation("messages", "dividerOr");
}
diff --git a/packages/angular/src/lib/components/country-selector.ts b/packages/angular/src/lib/components/country-selector.ts
index 4ac72704c..72c8969c2 100644
--- a/packages/angular/src/lib/components/country-selector.ts
+++ b/packages/angular/src/lib/components/country-selector.ts
@@ -47,9 +47,15 @@ import { injectCountries, injectDefaultCountry } from "../provider";
`,
})
+/**
+ * A country selector component for phone number input.
+ *
+ * Displays a dropdown with country flags, dial codes, and names for selecting a country.
+ */
export class CountrySelectorComponent {
countries = injectCountries();
defaultCountry = injectDefaultCountry();
+ /** The selected country code (two-way binding). */
value = model();
selected = computed(() => {
diff --git a/packages/angular/src/lib/components/divider.ts b/packages/angular/src/lib/components/divider.ts
index 40b3e43db..63c0ba8d3 100644
--- a/packages/angular/src/lib/components/divider.ts
+++ b/packages/angular/src/lib/components/divider.ts
@@ -34,6 +34,10 @@ import { CommonModule } from "@angular/common";
`,
})
+/**
+ * A divider component that can display a line or a line with text in the middle.
+ */
export class DividerComponent {
+ /** Optional label text to display in the center of the divider. */
label = input();
}
diff --git a/packages/angular/src/lib/components/form.ts b/packages/angular/src/lib/components/form.ts
index 034cb860c..856a96fa7 100644
--- a/packages/angular/src/lib/components/form.ts
+++ b/packages/angular/src/lib/components/form.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { Component, computed, input } from "@angular/core";
import { AnyFieldApi, AnyFormState, injectField } from "@tanstack/angular-form";
import { ButtonComponent } from "./button";
@@ -18,7 +34,11 @@ import { ButtonComponent } from "./button";
}
`,
})
+/**
+ * A component that displays form field metadata, such as validation errors.
+ */
export class FormMetadataComponent {
+ /** The form field API instance. */
field = input.required();
errors = computed(() =>
this.field()
@@ -60,10 +80,16 @@ export class FormMetadataComponent {
`,
})
+/**
+ * A form input component with label, description, and validation support.
+ */
export class FormInputComponent {
field = injectField();
+ /** The label text for the input field. */
label = input.required();
+ /** The input type (e.g., "text", "email", "password"). */
type = input("text");
+ /** Optional description text displayed below the label. */
description = input();
}
@@ -76,6 +102,9 @@ export class FormInputComponent {
},
template: ` `,
})
+/**
+ * A button component for form actions (e.g., "Forgot Password?" link).
+ */
export class FormActionComponent {}
@Component({
@@ -92,8 +121,15 @@ export class FormActionComponent {}
`,
})
+/**
+ * A submit button component for forms.
+ *
+ * Automatically disables when the form is submitting.
+ */
export class FormSubmitComponent {
+ /** Optional additional CSS classes. */
class = input();
+ /** The form state for tracking submission status. */
state = input.required();
isSubmitting = computed(() => this.state().isSubmitting);
@@ -113,7 +149,13 @@ export class FormSubmitComponent {
}
`,
})
+/**
+ * A component that displays form-level error messages.
+ *
+ * Shows errors from form submission, not validation errors.
+ */
export class FormErrorMessageComponent {
+ /** The form state containing error information. */
state = input.required();
errorMessage = computed(() => {
diff --git a/packages/angular/src/lib/components/logos/apple.ts b/packages/angular/src/lib/components/logos/apple.ts
index 7e9727b1d..5506447e7 100644
--- a/packages/angular/src/lib/components/logos/apple.ts
+++ b/packages/angular/src/lib/components/logos/apple.ts
@@ -30,8 +30,14 @@ import { Component, input } from "@angular/core";
`,
})
+/**
+ * The Apple logo SVG component.
+ */
export class AppleLogoComponent {
+ /** The width of the logo. */
width = input("1em");
+ /** The height of the logo. */
height = input("1em");
+ /** Optional additional CSS class names. */
className = input("");
}
diff --git a/packages/angular/src/lib/components/logos/facebook.ts b/packages/angular/src/lib/components/logos/facebook.ts
index 7812040d3..c022c5db1 100644
--- a/packages/angular/src/lib/components/logos/facebook.ts
+++ b/packages/angular/src/lib/components/logos/facebook.ts
@@ -30,8 +30,14 @@ import { Component, input } from "@angular/core";
`,
})
+/**
+ * The Facebook logo SVG component.
+ */
export class FacebookLogoComponent {
+ /** The width of the logo. */
width = input("1em");
+ /** The height of the logo. */
height = input("1em");
+ /** Optional additional CSS class names. */
className = input("");
}
diff --git a/packages/angular/src/lib/components/logos/github.ts b/packages/angular/src/lib/components/logos/github.ts
index fce4b33c6..bd417c8fd 100644
--- a/packages/angular/src/lib/components/logos/github.ts
+++ b/packages/angular/src/lib/components/logos/github.ts
@@ -29,8 +29,14 @@ import { Component, input } from "@angular/core";
`,
})
+/**
+ * The GitHub logo SVG component.
+ */
export class GithubLogoComponent {
+ /** The width of the logo. */
width = input("1em");
+ /** The height of the logo. */
height = input("1em");
+ /** Optional additional CSS class names. */
className = input("");
}
diff --git a/packages/angular/src/lib/components/logos/google.ts b/packages/angular/src/lib/components/logos/google.ts
index 8acab00de..805114852 100644
--- a/packages/angular/src/lib/components/logos/google.ts
+++ b/packages/angular/src/lib/components/logos/google.ts
@@ -42,8 +42,14 @@ import { Component, input } from "@angular/core";
`,
})
+/**
+ * The Google logo SVG component.
+ */
export class GoogleLogoComponent {
+ /** The width of the logo. */
width = input("1em");
+ /** The height of the logo. */
height = input("1em");
+ /** Optional additional CSS class names. */
className = input("");
}
diff --git a/packages/angular/src/lib/components/logos/index.ts b/packages/angular/src/lib/components/logos/index.ts
index 677873a2b..9385b0a33 100644
--- a/packages/angular/src/lib/components/logos/index.ts
+++ b/packages/angular/src/lib/components/logos/index.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
export { AppleLogoComponent } from "./apple";
export { FacebookLogoComponent } from "./facebook";
export { GithubLogoComponent } from "./github";
diff --git a/packages/angular/src/lib/components/logos/line.ts b/packages/angular/src/lib/components/logos/line.ts
index d3b98fd3f..ce7c69923 100644
--- a/packages/angular/src/lib/components/logos/line.ts
+++ b/packages/angular/src/lib/components/logos/line.ts
@@ -34,8 +34,14 @@ import { Component, input } from "@angular/core";
`,
})
+/**
+ * The Line logo SVG component.
+ */
export class LineLogoComponent {
+ /** The width of the logo. */
width = input("1em");
+ /** The height of the logo. */
height = input("1em");
+ /** Optional additional CSS class names. */
className = input("");
}
diff --git a/packages/angular/src/lib/components/logos/microsoft.ts b/packages/angular/src/lib/components/logos/microsoft.ts
index 88006fafe..c4563b0d8 100644
--- a/packages/angular/src/lib/components/logos/microsoft.ts
+++ b/packages/angular/src/lib/components/logos/microsoft.ts
@@ -30,8 +30,14 @@ import { Component, input } from "@angular/core";
`,
})
+/**
+ * The Microsoft logo SVG component.
+ */
export class MicrosoftLogoComponent {
+ /** The width of the logo. */
width = input("1em");
+ /** The height of the logo. */
height = input("1em");
+ /** Optional additional CSS class names. */
className = input("");
}
diff --git a/packages/angular/src/lib/components/logos/snapchat.ts b/packages/angular/src/lib/components/logos/snapchat.ts
index c11ec3c00..0b129fc39 100644
--- a/packages/angular/src/lib/components/logos/snapchat.ts
+++ b/packages/angular/src/lib/components/logos/snapchat.ts
@@ -30,8 +30,14 @@ import { Component, input } from "@angular/core";
`,
})
+/**
+ * The Snapchat logo SVG component.
+ */
export class SnapchatLogoComponent {
+ /** The width of the logo. */
width = input("1em");
+ /** The height of the logo. */
height = input("1em");
+ /** Optional additional CSS class names. */
className = input("");
}
diff --git a/packages/angular/src/lib/components/logos/twitter.ts b/packages/angular/src/lib/components/logos/twitter.ts
index 3acbbb71d..9630ea8e6 100644
--- a/packages/angular/src/lib/components/logos/twitter.ts
+++ b/packages/angular/src/lib/components/logos/twitter.ts
@@ -29,8 +29,14 @@ import { Component, input } from "@angular/core";
`,
})
+/**
+ * The Twitter/X logo SVG component.
+ */
export class TwitterLogoComponent {
+ /** The width of the logo. */
width = input("1em");
+ /** The height of the logo. */
height = input("1em");
+ /** Optional additional CSS class names. */
className = input("");
}
diff --git a/packages/angular/src/lib/components/policies.ts b/packages/angular/src/lib/components/policies.ts
index b8675b7e1..efe22bc16 100644
--- a/packages/angular/src/lib/components/policies.ts
+++ b/packages/angular/src/lib/components/policies.ts
@@ -48,6 +48,11 @@ type PolicyPart =
}
`,
})
+/**
+ * A component that displays terms of service and privacy policy links.
+ *
+ * Parses the terms and privacy policy template and renders clickable links.
+ */
export class PoliciesComponent {
private readonly policies = injectPolicies();
diff --git a/packages/angular/src/lib/components/redirect-error.ts b/packages/angular/src/lib/components/redirect-error.ts
index 224e5be99..9ef2a9bc7 100644
--- a/packages/angular/src/lib/components/redirect-error.ts
+++ b/packages/angular/src/lib/components/redirect-error.ts
@@ -30,6 +30,11 @@ import { injectRedirectError } from "../provider";
}
`,
})
+/**
+ * A component that displays redirect error messages.
+ *
+ * Shows errors that occurred during OAuth redirect flows.
+ */
export class RedirectErrorComponent {
error = injectRedirectError();
}
diff --git a/packages/angular/src/lib/provider.ts b/packages/angular/src/lib/provider.ts
index 0c1d1b480..41e1f75c9 100644
--- a/packages/angular/src/lib/provider.ts
+++ b/packages/angular/src/lib/provider.ts
@@ -53,11 +53,22 @@ import {
const FIREBASE_UI_STORE = new InjectionToken("firebaseui.store");
const FIREBASE_UI_POLICIES = new InjectionToken("firebaseui.policies");
+/** Configuration for terms of service and privacy policy links. */
type PolicyConfig = {
+ /** The URL to the terms of service page. */
termsOfServiceUrl: string;
+ /** The URL to the privacy policy page. */
privacyPolicyUrl: string;
};
+/**
+ * Provides FirebaseUI configuration for the Angular application.
+ *
+ * This function must be called in your application's providers array to enable FirebaseUI functionality.
+ *
+ * @param uiFactory - Factory function that creates a FirebaseUIStore from Firebase apps.
+ * @returns Environment providers for FirebaseUI.
+ */
export function provideFirebaseUI(uiFactory: (apps: FirebaseApps) => FirebaseUIStore): EnvironmentProviders {
const providers: Provider[] = [
// TODO: This should depend on the FirebaseAuth provider via deps,
@@ -78,12 +89,25 @@ export function provideFirebaseUI(uiFactory: (apps: FirebaseApps) => FirebaseUIS
return makeEnvironmentProviders(providers);
}
+/**
+ * Provides policy configuration (terms of service and privacy policy URLs) for FirebaseUI components.
+ *
+ * @param factory - Factory function that returns the policy configuration.
+ * @returns Environment providers for FirebaseUI policies.
+ */
export function provideFirebaseUIPolicies(factory: () => PolicyConfig) {
const providers: Provider[] = [{ provide: FIREBASE_UI_POLICIES, useFactory: factory }];
return makeEnvironmentProviders(providers);
}
+/**
+ * Injects the FirebaseUI store as a reactive signal.
+ *
+ * Returns a readonly signal that updates when the UI state changes.
+ *
+ * @returns A readonly signal containing the current FirebaseUI state.
+ */
export function injectUI() {
const store = inject(FIREBASE_UI_STORE);
const ui = signal(store.get());
@@ -95,6 +119,13 @@ export function injectUI() {
return ui.asReadonly();
}
+/**
+ * Injects a callback that is called when a user is authenticated.
+ *
+ * The callback is only triggered for non-anonymous users.
+ *
+ * @param onAuthenticated - Callback function called when a user is authenticated.
+ */
export function injectUserAuthenticated(onAuthenticated: (user: User) => void) {
const auth = inject(Auth);
const state = authState(auth);
@@ -112,6 +143,14 @@ export function injectUserAuthenticated(onAuthenticated: (user: User) => void) {
});
}
+/**
+ * Injects a reCAPTCHA verifier for phone authentication.
+ *
+ * Automatically renders the reCAPTCHA widget in the provided element when available.
+ *
+ * @param element - Function that returns the element reference where reCAPTCHA should be rendered.
+ * @returns A computed signal containing the reCAPTCHA verifier instance, or null if not available.
+ */
export function injectRecaptchaVerifier(element: () => ElementRef) {
const ui = injectUI();
const platformId = inject(PLATFORM_ID);
@@ -137,41 +176,85 @@ export function injectRecaptchaVerifier(element: () => ElementRef getTranslation(ui(), category as any, key as any));
}
+/**
+ * Injects the sign-in authentication form schema as a reactive signal.
+ *
+ * @returns A computed signal containing the sign-in form schema.
+ */
export function injectSignInAuthFormSchema(): Signal> {
const ui = injectUI();
return computed(() => createSignInAuthFormSchema(ui()));
}
+/**
+ * Injects the sign-up authentication form schema as a reactive signal.
+ *
+ * @returns A computed signal containing the sign-up form schema.
+ */
export function injectSignUpAuthFormSchema(): Signal> {
const ui = injectUI();
return computed(() => createSignUpAuthFormSchema(ui()));
}
+/**
+ * Injects the forgot password authentication form schema as a reactive signal.
+ *
+ * @returns A computed signal containing the forgot password form schema.
+ */
export function injectForgotPasswordAuthFormSchema(): Signal> {
const ui = injectUI();
return computed(() => createForgotPasswordAuthFormSchema(ui()));
}
+/**
+ * Injects the email link authentication form schema as a reactive signal.
+ *
+ * @returns A computed signal containing the email link auth form schema.
+ */
export function injectEmailLinkAuthFormSchema(): Signal> {
const ui = injectUI();
return computed(() => createEmailLinkAuthFormSchema(ui()));
}
+/**
+ * Injects the phone authentication number form schema as a reactive signal.
+ *
+ * @returns A computed signal containing the phone auth number form schema.
+ */
export function injectPhoneAuthFormSchema(): Signal> {
const ui = injectUI();
return computed(() => createPhoneAuthNumberFormSchema(ui()));
}
+/**
+ * Injects the phone authentication verification form schema as a reactive signal.
+ *
+ * @returns A computed signal containing the phone auth verification form schema.
+ */
export function injectPhoneAuthVerifyFormSchema(): Signal> {
const ui = injectUI();
return computed(() => createPhoneAuthVerifyFormSchema(ui()));
}
+/**
+ * Injects the multi-factor phone authentication number form schema as a reactive signal.
+ *
+ * @returns A computed signal containing the MFA phone auth number form schema.
+ */
export function injectMultiFactorPhoneAuthNumberFormSchema(): Signal<
ReturnType
> {
@@ -179,6 +262,11 @@ export function injectMultiFactorPhoneAuthNumberFormSchema(): Signal<
return computed(() => createMultiFactorPhoneAuthNumberFormSchema(ui()));
}
+/**
+ * Injects the multi-factor phone authentication assertion form schema as a reactive signal.
+ *
+ * @returns A computed signal containing the MFA phone auth assertion form schema.
+ */
export function injectMultiFactorPhoneAuthAssertionFormSchema(): Signal<
ReturnType
> {
@@ -186,6 +274,11 @@ export function injectMultiFactorPhoneAuthAssertionFormSchema(): Signal<
return computed(() => createMultiFactorPhoneAuthAssertionFormSchema(ui()));
}
+/**
+ * Injects the multi-factor phone authentication verification form schema as a reactive signal.
+ *
+ * @returns A computed signal containing the MFA phone auth verification form schema.
+ */
export function injectMultiFactorPhoneAuthVerifyFormSchema(): Signal<
ReturnType
> {
@@ -193,6 +286,11 @@ export function injectMultiFactorPhoneAuthVerifyFormSchema(): Signal<
return computed(() => createMultiFactorPhoneAuthVerifyFormSchema(ui()));
}
+/**
+ * Injects the multi-factor TOTP authentication number form schema as a reactive signal.
+ *
+ * @returns A computed signal containing the MFA TOTP auth number form schema.
+ */
export function injectMultiFactorTotpAuthNumberFormSchema(): Signal<
ReturnType
> {
@@ -200,6 +298,11 @@ export function injectMultiFactorTotpAuthNumberFormSchema(): Signal<
return computed(() => createMultiFactorTotpAuthNumberFormSchema(ui()));
}
+/**
+ * Injects the multi-factor TOTP authentication verification form schema as a reactive signal.
+ *
+ * @returns A computed signal containing the MFA TOTP auth verification form schema.
+ */
export function injectMultiFactorTotpAuthVerifyFormSchema(): Signal<
ReturnType
> {
@@ -207,20 +310,42 @@ export function injectMultiFactorTotpAuthVerifyFormSchema(): Signal<
return computed(() => createMultiFactorTotpAuthVerifyFormSchema(ui()));
}
+/**
+ * Injects the policy configuration (terms of service and privacy policy URLs).
+ *
+ * @returns The policy configuration, or null if not provided.
+ */
export function injectPolicies(): PolicyConfig | null {
return inject(FIREBASE_UI_POLICIES, { optional: true });
}
+/**
+ * Injects the list of allowed countries for phone authentication as a reactive signal.
+ *
+ * @returns A computed signal containing the array of allowed country data.
+ */
export function injectCountries(): Signal {
const ui = injectUI();
return computed(() => getBehavior(ui(), "countryCodes")().allowedCountries);
}
+/**
+ * Injects the default country for phone authentication as a reactive signal.
+ *
+ * @returns A computed signal containing the default country data.
+ */
export function injectDefaultCountry(): Signal {
const ui = injectUI();
return computed(() => getBehavior(ui(), "countryCodes")().defaultCountry);
}
+/**
+ * Injects the redirect error message as a reactive signal.
+ *
+ * Returns the error message if a redirect error occurred, undefined otherwise.
+ *
+ * @returns A computed signal containing the redirect error message, or undefined if no error.
+ */
export function injectRedirectError(): Signal {
const ui = injectUI();
return computed(() => {
diff --git a/packages/angular/src/lib/tests/test-helpers.ts b/packages/angular/src/lib/tests/test-helpers.ts
index f606320d8..8b8dd83cb 100644
--- a/packages/angular/src/lib/tests/test-helpers.ts
+++ b/packages/angular/src/lib/tests/test-helpers.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
// Mock implementations for @invertase/firebaseui-core to avoid ESM issues in tests
export const sendPasswordResetEmail = jest.fn();
export const sendSignInLinkToEmail = jest.fn();
diff --git a/packages/core/src/auth.test.ts b/packages/core/src/auth.test.ts
index 07908689a..692757355 100644
--- a/packages/core/src/auth.test.ts
+++ b/packages/core/src/auth.test.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import {
signInWithEmailAndPassword,
diff --git a/packages/core/src/auth.ts b/packages/core/src/auth.ts
index c8ab743cf..60b0bf08f 100644
--- a/packages/core/src/auth.ts
+++ b/packages/core/src/auth.ts
@@ -64,6 +64,16 @@ function setPendingState(ui: FirebaseUI) {
ui.setState("pending");
}
+/**
+ * Signs in with an email and password.
+ *
+ * If the `autoUpgradeAnonymousUsers` behavior is enabled, it will attempt to upgrade an anonymous user to a regular user.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @param email - The email to sign in with.
+ * @param password - The password to sign in with.
+ * @returns {Promise} A promise containing the user credential.
+ */
export async function signInWithEmailAndPassword(
ui: FirebaseUI,
email: string,
@@ -90,6 +100,18 @@ export async function signInWithEmailAndPassword(
}
}
+/**
+ * Creates a new user account with an email and password.
+ *
+ * If the `requireDisplayName` behavior is enabled, a display name must be provided.
+ * If the `autoUpgradeAnonymousUsers` behavior is enabled, it will attempt to upgrade an anonymous user to a regular user.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @param email - The email address for the new account.
+ * @param password - The password for the new account.
+ * @param displayName - Optional display name for the user.
+ * @returns {Promise} A promise containing the user credential.
+ */
export async function createUserWithEmailAndPassword(
ui: FirebaseUI,
email: string,
@@ -130,6 +152,18 @@ export async function createUserWithEmailAndPassword(
}
}
+/**
+ * Verifies a phone number for authentication.
+ *
+ * Supports regular phone authentication, MFA enrollment, and MFA assertion flows.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @param phoneNumber - The phone number to verify.
+ * @param appVerifier - The application verifier (reCAPTCHA).
+ * @param mfaUser - Optional multi-factor user for MFA enrollment flow.
+ * @param mfaHint - Optional multi-factor info hint for MFA assertion flow.
+ * @returns {Promise} A promise containing the verification ID.
+ */
export async function verifyPhoneNumber(
ui: FirebaseUI,
phoneNumber: string,
@@ -171,6 +205,16 @@ export async function verifyPhoneNumber(
}
}
+/**
+ * Confirms a phone number verification code and signs in the user.
+ *
+ * If the `autoUpgradeAnonymousUsers` behavior is enabled and the current user is anonymous, it will attempt to upgrade the anonymous user to a regular user.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @param verificationId - The verification ID from the phone verification process.
+ * @param verificationCode - The verification code sent to the phone.
+ * @returns {Promise} A promise containing the user credential.
+ */
export async function confirmPhoneNumber(
ui: FirebaseUI,
verificationId: string,
@@ -198,6 +242,13 @@ export async function confirmPhoneNumber(
}
}
+/**
+ * Sends a password reset email to the specified email address.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @param email - The email address to send the password reset email to.
+ * @returns {Promise} A promise that resolves when the email is sent.
+ */
export async function sendPasswordResetEmail(ui: FirebaseUI, email: string): Promise {
try {
setPendingState(ui);
@@ -209,6 +260,15 @@ export async function sendPasswordResetEmail(ui: FirebaseUI, email: string): Pro
}
}
+/**
+ * Sends a sign-in link to the specified email address.
+ *
+ * The email address is stored in localStorage for later use during the sign-in process.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @param email - The email address to send the sign-in link to.
+ * @returns {Promise} A promise that resolves when the email is sent.
+ */
export async function sendSignInLinkToEmail(ui: FirebaseUI, email: string): Promise {
try {
setPendingState(ui);
@@ -228,11 +288,28 @@ export async function sendSignInLinkToEmail(ui: FirebaseUI, email: string): Prom
}
}
+/**
+ * Signs in a user using an email link.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @param email - The email address associated with the sign-in link.
+ * @param link - The sign-in link from the email.
+ * @returns {Promise} A promise containing the user credential.
+ */
export async function signInWithEmailLink(ui: FirebaseUI, email: string, link: string): Promise {
const credential = EmailAuthProvider.credentialWithLink(email, link);
return signInWithCredential(ui, credential);
}
+/**
+ * Signs in a user with an authentication credential.
+ *
+ * If the `autoUpgradeAnonymousUsers` behavior is enabled, it will attempt to upgrade an anonymous user to a regular user.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @param credential - The authentication credential to sign in with.
+ * @returns {Promise} A promise containing the user credential.
+ */
export async function signInWithCredential(ui: FirebaseUI, credential: AuthCredential): Promise {
try {
setPendingState(ui);
@@ -255,6 +332,13 @@ export async function signInWithCredential(ui: FirebaseUI, credential: AuthCrede
}
}
+/**
+ * Signs in a user with a custom token.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @param customToken - The custom token to sign in with.
+ * @returns {Promise} A promise containing the user credential.
+ */
export async function signInWithCustomToken(ui: FirebaseUI, customToken: string): Promise {
try {
setPendingState(ui);
@@ -267,6 +351,12 @@ export async function signInWithCustomToken(ui: FirebaseUI, customToken: string)
}
}
+/**
+ * Signs in a user anonymously.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @returns {Promise} A promise containing the user credential.
+ */
export async function signInAnonymously(ui: FirebaseUI): Promise {
try {
setPendingState(ui);
@@ -279,6 +369,16 @@ export async function signInAnonymously(ui: FirebaseUI): Promise
}
}
+/**
+ * Signs in a user with an authentication provider (e.g., Google, Facebook, etc.).
+ *
+ * If the `autoUpgradeAnonymousProvider` behavior is enabled, it will attempt to upgrade an anonymous user to a regular user.
+ * The sign-in strategy (popup or redirect) is determined by the `providerSignInStrategy` behavior.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @param provider - The authentication provider to sign in with.
+ * @returns {Promise} A promise containing the user credential, or never if using redirect strategy.
+ */
export async function signInWithProvider(ui: FirebaseUI, provider: AuthProvider): Promise {
try {
setPendingState(ui);
@@ -305,6 +405,16 @@ export async function signInWithProvider(ui: FirebaseUI, provider: AuthProvider)
}
}
+/**
+ * Completes the email link sign-in process using the current URL.
+ *
+ * Checks if the current URL is a valid email link sign-in URL and retrieves the email from localStorage.
+ * Returns null if the URL is not a valid email link or if no email is found in localStorage.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @param currentUrl - The current URL to check for email link sign-in.
+ * @returns {Promise} A promise containing the user credential, or null if the sign-in cannot be completed.
+ */
export async function completeEmailLinkSignIn(ui: FirebaseUI, currentUrl: string): Promise {
try {
if (!_isSignInWithEmailLink(ui.auth, currentUrl)) {
@@ -322,6 +432,18 @@ export async function completeEmailLinkSignIn(ui: FirebaseUI, currentUrl: string
}
}
+/**
+ * Generates a QR code data URL for TOTP (Time-based One-Time Password) multi-factor authentication.
+ *
+ * The QR code can be scanned by an authenticator app to set up TOTP MFA for the user.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @param secret - The TOTP secret to generate the QR code for.
+ * @param accountName - Optional account name for the QR code. Defaults to the user's email if not provided.
+ * @param issuer - Optional issuer name for the QR code.
+ * @returns {string} A data URL containing the QR code image.
+ * @throws {Error} Throws an error if the user is not authenticated.
+ */
export function generateTotpQrCode(ui: FirebaseUI, secret: TotpSecret, accountName?: string, issuer?: string): string {
const currentUser = ui.auth.currentUser;
@@ -337,6 +459,15 @@ export function generateTotpQrCode(ui: FirebaseUI, secret: TotpSecret, accountNa
return qr.createDataURL();
}
+/**
+ * Signs in a user using a multi-factor assertion.
+ *
+ * Resolves the multi-factor challenge using the provided assertion and clears the multi-factor resolver from the UI state.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @param assertion - The multi-factor assertion to use for sign-in.
+ * @returns {Promise} A promise containing the user credential.
+ */
export async function signInWithMultiFactorAssertion(ui: FirebaseUI, assertion: MultiFactorAssertion) {
try {
setPendingState(ui);
@@ -350,6 +481,14 @@ export async function signInWithMultiFactorAssertion(ui: FirebaseUI, assertion:
}
}
+/**
+ * Enrolls a multi-factor authentication method for the current user.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @param assertion - The multi-factor assertion to enroll.
+ * @param displayName - Optional display name for the enrolled MFA method.
+ * @returns {Promise} A promise that resolves when the enrollment is complete.
+ */
export async function enrollWithMultiFactorAssertion(
ui: FirebaseUI,
assertion: MultiFactorAssertion,
@@ -365,6 +504,12 @@ export async function enrollWithMultiFactorAssertion(
}
}
+/**
+ * Generates a TOTP (Time-based One-Time Password) secret for multi-factor authentication enrollment.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @returns {Promise} A promise containing the TOTP secret.
+ */
export async function generateTotpSecret(ui: FirebaseUI): Promise {
try {
setPendingState(ui);
diff --git a/packages/core/src/behaviors/anonymous-upgrade.test.ts b/packages/core/src/behaviors/anonymous-upgrade.test.ts
index a8e6fdaee..e551a25ad 100644
--- a/packages/core/src/behaviors/anonymous-upgrade.test.ts
+++ b/packages/core/src/behaviors/anonymous-upgrade.test.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { describe, it, expect, vi, beforeEach } from "vitest";
import {
Auth,
diff --git a/packages/core/src/behaviors/anonymous-upgrade.ts b/packages/core/src/behaviors/anonymous-upgrade.ts
index ce534de17..1f93fc311 100644
--- a/packages/core/src/behaviors/anonymous-upgrade.ts
+++ b/packages/core/src/behaviors/anonymous-upgrade.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { type AuthCredential, type AuthProvider, linkWithCredential, type UserCredential } from "firebase/auth";
import { type FirebaseUI } from "~/config";
import { getBehavior } from "~/behaviors";
diff --git a/packages/core/src/behaviors/auto-anonymous-login.test.ts b/packages/core/src/behaviors/auto-anonymous-login.test.ts
index 9dd033a96..c2648a284 100644
--- a/packages/core/src/behaviors/auto-anonymous-login.test.ts
+++ b/packages/core/src/behaviors/auto-anonymous-login.test.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { describe, it, expect, vi, beforeEach } from "vitest";
import { Auth, signInAnonymously, User } from "firebase/auth";
import { autoAnonymousLoginHandler } from "./auto-anonymous-login";
diff --git a/packages/core/src/behaviors/auto-anonymous-login.ts b/packages/core/src/behaviors/auto-anonymous-login.ts
index 8d625f383..f2bf23cff 100644
--- a/packages/core/src/behaviors/auto-anonymous-login.ts
+++ b/packages/core/src/behaviors/auto-anonymous-login.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { signInAnonymously } from "firebase/auth";
import { type InitHandler } from "./utils";
diff --git a/packages/core/src/behaviors/country-codes.test.ts b/packages/core/src/behaviors/country-codes.test.ts
index b348b0556..b3c5cce8a 100644
--- a/packages/core/src/behaviors/country-codes.test.ts
+++ b/packages/core/src/behaviors/country-codes.test.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { describe, it, expect, vi } from "vitest";
import { countryCodesHandler, CountryCodesOptions } from "./country-codes";
import { countryData } from "../country-data";
diff --git a/packages/core/src/behaviors/country-codes.ts b/packages/core/src/behaviors/country-codes.ts
index 4c3e503aa..a4965f621 100644
--- a/packages/core/src/behaviors/country-codes.ts
+++ b/packages/core/src/behaviors/country-codes.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { type CountryCode, countryData } from "../country-data";
export type CountryCodesOptions = {
diff --git a/packages/core/src/behaviors/index.test.ts b/packages/core/src/behaviors/index.test.ts
index 305b289d1..0994558eb 100644
--- a/packages/core/src/behaviors/index.test.ts
+++ b/packages/core/src/behaviors/index.test.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { describe, it, expect, vi, beforeEach } from "vitest";
import { createMockUI } from "~/tests/utils";
import {
diff --git a/packages/core/src/behaviors/index.ts b/packages/core/src/behaviors/index.ts
index 417fa0564..5841d41e5 100644
--- a/packages/core/src/behaviors/index.ts
+++ b/packages/core/src/behaviors/index.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import type { FirebaseUI } from "~/config";
import type { RecaptchaVerifier, UserCredential } from "firebase/auth";
import * as anonymousUpgradeHandlers from "./anonymous-upgrade";
@@ -37,19 +53,37 @@ type Registry = {
countryCodes: CallableBehavior;
};
+/** A behavior or set of behaviors from the registry. */
export type Behavior = Pick;
+/** All available behaviors, with each behavior being optional. */
export type Behaviors = Partial;
+/**
+ * Enables automatic anonymous login when the app initializes.
+ *
+ * @returns A behavior that automatically signs in users anonymously on app initialization.
+ */
export function autoAnonymousLogin(): Behavior<"autoAnonymousLogin"> {
return {
autoAnonymousLogin: initBehavior(autoAnonymousLoginHandlers.autoAnonymousLoginHandler),
};
}
+/** Options for the auto-upgrade anonymous users behavior. */
export type AutoUpgradeAnonymousUsersOptions = {
+ /** Optional callback function that is called when an anonymous user is upgraded. */
onUpgrade?: anonymousUpgradeHandlers.OnUpgradeCallback;
};
+/**
+ * Automatically upgrades anonymous users to regular users when they sign in with a credential or provider.
+ *
+ * This behavior handles upgrading anonymous users for credential-based sign-ins, provider-based sign-ins,
+ * and redirect-based authentication flows.
+ *
+ * @param options - Optional configuration including an upgrade callback.
+ * @returns Behaviors for automatically upgrading anonymous users.
+ */
export function autoUpgradeAnonymousUsers(
options?: AutoUpgradeAnonymousUsersOptions
): Behavior<
@@ -68,8 +102,15 @@ export function autoUpgradeAnonymousUsers(
};
}
+/** Options for reCAPTCHA verification behavior. */
export type RecaptchaVerificationOptions = recaptchaHandlers.RecaptchaVerificationOptions;
+/**
+ * Configures reCAPTCHA verification for phone authentication.
+ *
+ * @param options - Optional reCAPTCHA verification options.
+ * @returns A behavior that handles reCAPTCHA verification for phone authentication.
+ */
export function recaptchaVerification(options?: RecaptchaVerificationOptions): Behavior<"recaptchaVerification"> {
return {
recaptchaVerification: callableBehavior((ui, element) =>
@@ -78,6 +119,11 @@ export function recaptchaVerification(options?: RecaptchaVerificationOptions): B
};
}
+/**
+ * Configures provider authentication to use redirect strategy instead of popup.
+ *
+ * @returns Behaviors for provider sign-in and linking using redirect strategy.
+ */
export function providerRedirectStrategy(): Behavior<"providerSignInStrategy" | "providerLinkStrategy"> {
return {
providerSignInStrategy: callableBehavior(providerStrategyHandlers.signInWithRediectHandler),
@@ -85,6 +131,13 @@ export function providerRedirectStrategy(): Behavior<"providerSignInStrategy" |
};
}
+/**
+ * Configures provider authentication to use popup strategy instead of redirect.
+ *
+ * This is the default strategy for provider authentication.
+ *
+ * @returns Behaviors for provider sign-in and linking using popup strategy.
+ */
export function providerPopupStrategy(): Behavior<"providerSignInStrategy" | "providerLinkStrategy"> {
return {
providerSignInStrategy: callableBehavior(providerStrategyHandlers.signInWithPopupHandler),
@@ -92,30 +145,63 @@ export function providerPopupStrategy(): Behavior<"providerSignInStrategy" | "pr
};
}
+/** Options for Google One Tap sign-in behavior. */
export type OneTapSignInOptions = oneTapSignInHandlers.OneTapSignInOptions;
+/**
+ * Enables Google One Tap sign-in functionality.
+ *
+ * @param options - Configuration options for Google One Tap sign-in.
+ * @returns A behavior that handles Google One Tap sign-in initialization.
+ */
export function oneTapSignIn(options: OneTapSignInOptions): Behavior<"oneTapSignIn"> {
return {
oneTapSignIn: initBehavior((ui) => oneTapSignInHandlers.oneTapSignInHandler(ui, options)),
};
}
+/**
+ * Requires users to provide a display name when creating an account.
+ *
+ * @returns A behavior that enforces display name requirement during user registration.
+ */
export function requireDisplayName(): Behavior<"requireDisplayName"> {
return {
requireDisplayName: callableBehavior(requireDisplayNameHandlers.requireDisplayNameHandler),
};
}
+/**
+ * Configures country code selection for phone number input.
+ *
+ * @param options - Optional configuration for country code behavior.
+ * @returns A behavior that provides country code functionality for phone authentication.
+ */
export function countryCodes(options?: countryCodesHandlers.CountryCodesOptions): Behavior<"countryCodes"> {
return {
countryCodes: callableBehavior(() => countryCodesHandlers.countryCodesHandler(options)),
};
}
+/**
+ * Checks if a specific behavior is enabled for the given FirebaseUI instance.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @param key - The behavior key to check.
+ * @returns True if the behavior is enabled, false otherwise.
+ */
export function hasBehavior(ui: FirebaseUI, key: T): boolean {
return !!ui.behaviors[key];
}
+/**
+ * Gets the handler function for a specific behavior.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @param key - The behavior key to retrieve.
+ * @returns The handler function for the specified behavior.
+ * @throws {Error} Throws an error if the behavior is not found.
+ */
export function getBehavior(ui: FirebaseUI, key: T): Registry[T]["handler"] {
if (!hasBehavior(ui, key)) {
throw new Error(`Behavior ${key} not found`);
@@ -124,6 +210,7 @@ export function getBehavior(ui: FirebaseUI, key: T): R
return (ui.behaviors[key] as Registry[T]).handler;
}
+/** Default behaviors that are enabled by default for all FirebaseUI instances. */
export const defaultBehaviors: Behavior<"recaptchaVerification"> = {
...recaptchaVerification(),
...providerPopupStrategy(),
diff --git a/packages/core/src/behaviors/one-tap.test.ts b/packages/core/src/behaviors/one-tap.test.ts
index 43a6c7de6..6017b28b7 100644
--- a/packages/core/src/behaviors/one-tap.test.ts
+++ b/packages/core/src/behaviors/one-tap.test.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { Auth, User } from "firebase/auth";
import { oneTapSignInHandler, type OneTapSignInOptions } from "./one-tap";
diff --git a/packages/core/src/behaviors/one-tap.ts b/packages/core/src/behaviors/one-tap.ts
index 5154a4f79..93d608f38 100644
--- a/packages/core/src/behaviors/one-tap.ts
+++ b/packages/core/src/behaviors/one-tap.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { GoogleAuthProvider } from "firebase/auth";
import type { IdConfiguration } from "google-one-tap";
import type { FirebaseUI } from "~/config";
diff --git a/packages/core/src/behaviors/provider-strategy.test.ts b/packages/core/src/behaviors/provider-strategy.test.ts
index 9eda32cb1..08a158687 100644
--- a/packages/core/src/behaviors/provider-strategy.test.ts
+++ b/packages/core/src/behaviors/provider-strategy.test.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { describe, it, expect, vi, beforeEach } from "vitest";
import {
Auth,
diff --git a/packages/core/src/behaviors/provider-strategy.ts b/packages/core/src/behaviors/provider-strategy.ts
index 32c395ac6..a0f02ab9c 100644
--- a/packages/core/src/behaviors/provider-strategy.ts
+++ b/packages/core/src/behaviors/provider-strategy.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import {
type AuthProvider,
linkWithPopup,
diff --git a/packages/core/src/behaviors/recaptcha.test.ts b/packages/core/src/behaviors/recaptcha.test.ts
index 08fce46f2..543e176bc 100644
--- a/packages/core/src/behaviors/recaptcha.test.ts
+++ b/packages/core/src/behaviors/recaptcha.test.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { describe, it, expect, vi, beforeEach } from "vitest";
import { RecaptchaVerifier } from "firebase/auth";
import { recaptchaVerificationHandler, type RecaptchaVerificationOptions } from "./recaptcha";
diff --git a/packages/core/src/behaviors/recaptcha.ts b/packages/core/src/behaviors/recaptcha.ts
index 707070ee2..206b0087e 100644
--- a/packages/core/src/behaviors/recaptcha.ts
+++ b/packages/core/src/behaviors/recaptcha.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { RecaptchaVerifier } from "firebase/auth";
import { type FirebaseUI } from "~/config";
diff --git a/packages/core/src/behaviors/require-display-name.test.ts b/packages/core/src/behaviors/require-display-name.test.ts
index e9134de0f..8e0b207b7 100644
--- a/packages/core/src/behaviors/require-display-name.test.ts
+++ b/packages/core/src/behaviors/require-display-name.test.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { describe, it, expect, vi, beforeEach } from "vitest";
import { User } from "firebase/auth";
import { requireDisplayNameHandler } from "./require-display-name";
diff --git a/packages/core/src/behaviors/require-display-name.ts b/packages/core/src/behaviors/require-display-name.ts
index 1402d1a48..d40ad177d 100644
--- a/packages/core/src/behaviors/require-display-name.ts
+++ b/packages/core/src/behaviors/require-display-name.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { updateProfile, type User } from "firebase/auth";
import { type FirebaseUI } from "~/config";
diff --git a/packages/core/src/behaviors/utils.test.ts b/packages/core/src/behaviors/utils.test.ts
index abfc34c0a..f37afc51f 100644
--- a/packages/core/src/behaviors/utils.test.ts
+++ b/packages/core/src/behaviors/utils.test.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { describe, it, expect, vi, beforeEach } from "vitest";
import {
callableBehavior,
diff --git a/packages/core/src/behaviors/utils.ts b/packages/core/src/behaviors/utils.ts
index 7d332e7a7..6f30e39c6 100644
--- a/packages/core/src/behaviors/utils.ts
+++ b/packages/core/src/behaviors/utils.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import type { UserCredential } from "firebase/auth";
import type { FirebaseUI } from "~/config";
diff --git a/packages/core/src/config.test.ts b/packages/core/src/config.test.ts
index 1312c8ca9..84bb48859 100644
--- a/packages/core/src/config.test.ts
+++ b/packages/core/src/config.test.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { FirebaseApp } from "firebase/app";
import { Auth, MultiFactorResolver } from "firebase/auth";
import { describe, it, expect, vi, beforeEach } from "vitest";
diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts
index 43655865c..b342c03a5 100644
--- a/packages/core/src/config.ts
+++ b/packages/core/src/config.ts
@@ -23,32 +23,82 @@ import type { InitBehavior, RedirectBehavior } from "./behaviors/utils";
import { type FirebaseUIState } from "./state";
import { handleFirebaseError } from "./errors";
+/**
+ * Configuration options for initializing FirebaseUI.
+ */
export type FirebaseUIOptions = {
+ /** A required Firebase App instance, e.g. from `initializeApp`. */
app: FirebaseApp;
+ /** An optional Firebase Auth instance, e.g. from `getAuth`. If not provided, it will be created using the app instance. */
auth?: Auth;
+ /** A default locale to use. Defaults to `enUs`. */
locale?: RegisteredLocale;
+ /** An optional array of behaviors, e.g. from `requireDisplayName`. */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
behaviors?: Behavior[];
};
+/**
+ * The main FirebaseUI instance that provides access to Firebase Auth and UI state management.
+ *
+ * This type encapsulates all the necessary components for managing authentication UI state,
+ * including Firebase app and auth instances, locale settings, behaviors, and multi-factor
+ * authentication state.
+ */
export type FirebaseUI = {
+ /** The Firebase App instance. */
app: FirebaseApp;
+ /** The Firebase Auth instance. */
auth: Auth;
+ /** Sets the locale for translations. */
setLocale: (locale: RegisteredLocale) => void;
+ /** The current UI state (e.g., "idle", "pending", "loading"). */
state: FirebaseUIState;
+ /** Sets the UI state. */
setState: (state: FirebaseUIState) => void;
+ /** The current locale for translations. */
locale: RegisteredLocale;
+ /** The configured behaviors that customize authentication flows. */
behaviors: Behaviors;
+ /** The multi-factor resolver, if a multi-factor challenge is in progress. */
multiFactorResolver?: MultiFactorResolver;
+ /** Sets the multi-factor resolver. */
setMultiFactorResolver: (multiFactorResolver?: MultiFactorResolver) => void;
+ /** Any error that occurred during a redirect-based authentication flow. */
redirectError?: Error;
+ /** Sets the redirect error. */
setRedirectError: (error?: Error) => void;
};
export const $config = map>>({});
+/**
+ * A reactive store containing a FirebaseUI instance.
+ *
+ * This store allows for reactive updates to the FirebaseUI state, enabling UI components
+ * to automatically update when the authentication state or configuration changes.
+ */
export type FirebaseUIStore = DeepMapStore;
+/**
+ * Initializes a FirebaseUI instance with the provided configuration.
+ *
+ * Creates a reactive store containing the FirebaseUI instance, sets up behaviors,
+ * and handles initialization and redirect flows if running client-side.
+ *
+ * Example:
+ * ```typescript
+ * const ui = initializeUI({
+ * app: firebaseApp,
+ * locale: enUs,
+ * behaviors: [requireDisplayName()],
+ * });
+ * ```
+ *
+ * @param config - The configuration options for FirebaseUI.
+ * @param name - Optional name for the FirebaseUI instance. Defaults to "[DEFAULT]".
+ * @returns {FirebaseUIStore} A reactive store containing the initialized FirebaseUI instance.
+ */
export function initializeUI(config: FirebaseUIOptions, name: string = "[DEFAULT]"): FirebaseUIStore {
// Reduce the behaviors to a single object.
const behaviors = config.behaviors?.reduce((acc, behavior) => {
diff --git a/packages/core/src/country-data.test.ts b/packages/core/src/country-data.test.ts
index d13bc7c8f..6a23cb81f 100644
--- a/packages/core/src/country-data.test.ts
+++ b/packages/core/src/country-data.test.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { describe, it, expect } from "vitest";
import { countryData, formatPhoneNumber, CountryData, CountryCode } from "./country-data";
diff --git a/packages/core/src/country-data.ts b/packages/core/src/country-data.ts
index 20a563473..ddc4915a8 100644
--- a/packages/core/src/country-data.ts
+++ b/packages/core/src/country-data.ts
@@ -16,6 +16,9 @@
import { formatIncompletePhoneNumber, parsePhoneNumberWithError, type CountryCode } from "libphonenumber-js";
+/**
+ * An array of country data objects containing name, dial code, country code, and emoji for all supported countries.
+ */
export const countryData = [
{ name: "Afghanistan", dialCode: "+93", code: "AF", emoji: "🇦🇫" },
{ name: "Albania", dialCode: "+355", code: "AL", emoji: "🇦🇱" },
@@ -265,15 +268,29 @@ export const countryData = [
{ name: "Åland Islands", dialCode: "+358", code: "AX", emoji: "🇦🇽" },
] as const satisfies CountryData[];
+/**
+ * A country data object containing name, dial code, country code, and emoji for a supported country.
+ */
export type CountryData = {
+ /** The name of the country. */
name: string;
+ /** The dial code of the country. */
dialCode: string;
+ /** The country code of the country. */
code: CountryCode;
+ /** The emoji of the country. */
emoji: string;
};
export type { CountryCode };
+/**
+ * Formats a phone number according to the specified country data.
+ *
+ * @param phoneNumber - The phone number to format.
+ * @param countryData - The country data to use for formatting.
+ * @returns {string} The formatted phone number in E164 format.
+ */
export function formatPhoneNumber(phoneNumber: string, countryData: CountryData): string {
try {
const parsedNumber = parsePhoneNumberWithError(phoneNumber, countryData.code);
diff --git a/packages/core/src/errors.test.ts b/packages/core/src/errors.test.ts
index a4226ea2b..c59f5b264 100644
--- a/packages/core/src/errors.test.ts
+++ b/packages/core/src/errors.test.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { describe, it, expect, vi, beforeEach } from "vitest";
import { FirebaseError } from "firebase/app";
import { Auth, AuthCredential, MultiFactorResolver } from "firebase/auth";
diff --git a/packages/core/src/errors.ts b/packages/core/src/errors.ts
index 782f2191d..ec1fe1e7c 100644
--- a/packages/core/src/errors.ts
+++ b/packages/core/src/errors.ts
@@ -19,6 +19,10 @@ import { FirebaseError } from "firebase/app";
import { type AuthCredential, getMultiFactorResolver, type MultiFactorError } from "firebase/auth";
import { type FirebaseUI } from "./config";
import { getTranslation } from "./translations";
+
+/**
+ * A custom error class that extends FirebaseError and provides a translated error message based on the configured locale.
+ */
export class FirebaseUIError extends FirebaseError {
constructor(ui: FirebaseUI, error: FirebaseError) {
const message = getTranslation(ui, "errors", ERROR_CODE_MAP[error.code as ErrorCode]);
@@ -29,6 +33,17 @@ export class FirebaseUIError extends FirebaseError {
}
}
+/**
+ * Handles a Firebase error and throws a FirebaseUIError if it is a Firebase error.
+ *
+ * Addtionally, handles the following error codes:
+ * - auth/account-exists-with-different-credential - stores the credential in sessionStorage.
+ * - auth/multi-factor-auth-required - updates the UI instance with the multi-factor resolver.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @param error - The error to handle.
+ * @returns {never} A never type.
+ */
export function handleFirebaseError(ui: FirebaseUI, error: unknown): never {
// If it's not a Firebase error, then we just throw it and preserve the original error.
if (!isFirebaseError(error)) {
diff --git a/packages/core/src/register-framework.test.ts b/packages/core/src/register-framework.test.ts
index 30b0f16c8..c9034626c 100644
--- a/packages/core/src/register-framework.test.ts
+++ b/packages/core/src/register-framework.test.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { describe, it, expect, vi, beforeEach } from "vitest";
import { registerFramework } from "./register-framework";
diff --git a/packages/core/src/register-framework.ts b/packages/core/src/register-framework.ts
index 3817ad7c0..dce604e81 100644
--- a/packages/core/src/register-framework.ts
+++ b/packages/core/src/register-framework.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { registerVersion } from "firebase/app";
/**
diff --git a/packages/core/src/schemas.test.ts b/packages/core/src/schemas.test.ts
index 13edc30e3..4f215193d 100644
--- a/packages/core/src/schemas.test.ts
+++ b/packages/core/src/schemas.test.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { describe, it, expect, vi } from "vitest";
import { createMockUI } from "~/tests/utils";
import {
diff --git a/packages/core/src/schemas.ts b/packages/core/src/schemas.ts
index 509193d99..2e03b42ca 100644
--- a/packages/core/src/schemas.ts
+++ b/packages/core/src/schemas.ts
@@ -19,10 +19,14 @@ import { getTranslation } from "./translations";
import { type FirebaseUI } from "./config";
import { hasBehavior } from "./behaviors";
-export const LoginTypes = ["email", "phone", "anonymous", "emailLink", "google"] as const;
-export type LoginType = (typeof LoginTypes)[number];
-export type AuthMode = "signIn" | "signUp";
-
+/**
+ * Creates a Zod schema for sign-in form validation.
+ *
+ * Validates email format and password minimum length (6 characters).
+ *
+ * @param ui - The FirebaseUI instance.
+ * @returns A Zod schema for sign-in form validation.
+ */
export function createSignInAuthFormSchema(ui: FirebaseUI) {
return z.object({
email: z.email(getTranslation(ui, "errors", "invalidEmail")),
@@ -30,6 +34,15 @@ export function createSignInAuthFormSchema(ui: FirebaseUI) {
});
}
+/**
+ * Creates a Zod schema for sign-up form validation.
+ *
+ * Validates email format, password minimum length (6 characters), and optionally requires a display name
+ * if the `requireDisplayName` behavior is enabled.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @returns A Zod schema for sign-up form validation.
+ */
export function createSignUpAuthFormSchema(ui: FirebaseUI) {
const requireDisplayName = hasBehavior(ui, "requireDisplayName");
const displayNameRequiredMessage = getTranslation(ui, "errors", "displayNameRequired");
@@ -43,18 +56,42 @@ export function createSignUpAuthFormSchema(ui: FirebaseUI) {
});
}
+/**
+ * Creates a Zod schema for forgot password form validation.
+ *
+ * Validates email format.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @returns A Zod schema for forgot password form validation.
+ */
export function createForgotPasswordAuthFormSchema(ui: FirebaseUI) {
return z.object({
email: z.email(getTranslation(ui, "errors", "invalidEmail")),
});
}
+/**
+ * Creates a Zod schema for email link authentication form validation.
+ *
+ * Validates email format.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @returns A Zod schema for email link authentication form validation.
+ */
export function createEmailLinkAuthFormSchema(ui: FirebaseUI) {
return z.object({
email: z.email(getTranslation(ui, "errors", "invalidEmail")),
});
}
+/**
+ * Creates a Zod schema for phone number form validation.
+ *
+ * Validates that the phone number is provided and has a maximum length of 10 characters.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @returns A Zod schema for phone number form validation.
+ */
export function createPhoneAuthNumberFormSchema(ui: FirebaseUI) {
return z.object({
phoneNumber: z
@@ -64,6 +101,14 @@ export function createPhoneAuthNumberFormSchema(ui: FirebaseUI) {
});
}
+/**
+ * Creates a Zod schema for phone verification code form validation.
+ *
+ * Validates that the verification ID is provided and the verification code is at least 6 characters long.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @returns A Zod schema for phone verification form validation.
+ */
export function createPhoneAuthVerifyFormSchema(ui: FirebaseUI) {
return z.object({
verificationId: z.string().min(1, getTranslation(ui, "errors", "missingVerificationId")),
@@ -73,6 +118,14 @@ export function createPhoneAuthVerifyFormSchema(ui: FirebaseUI) {
});
}
+/**
+ * Creates a Zod schema for multi-factor phone authentication number form validation.
+ *
+ * Extends the phone number schema with a required display name field.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @returns A Zod schema for multi-factor phone authentication number form validation.
+ */
export function createMultiFactorPhoneAuthNumberFormSchema(ui: FirebaseUI) {
const base = createPhoneAuthNumberFormSchema(ui);
return base.extend({
@@ -80,20 +133,52 @@ export function createMultiFactorPhoneAuthNumberFormSchema(ui: FirebaseUI) {
});
}
+/**
+ * Creates a Zod schema for multi-factor phone authentication assertion form validation.
+ *
+ * Uses the same validation as the phone number form schema.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @returns A Zod schema for multi-factor phone authentication assertion form validation.
+ */
export function createMultiFactorPhoneAuthAssertionFormSchema(ui: FirebaseUI) {
return createPhoneAuthNumberFormSchema(ui);
}
+/**
+ * Creates a Zod schema for multi-factor phone authentication verification form validation.
+ *
+ * Uses the same validation as the phone verification form schema.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @returns A Zod schema for multi-factor phone authentication verification form validation.
+ */
export function createMultiFactorPhoneAuthVerifyFormSchema(ui: FirebaseUI) {
return createPhoneAuthVerifyFormSchema(ui);
}
+/**
+ * Creates a Zod schema for multi-factor TOTP authentication number form validation.
+ *
+ * Validates that a display name is provided.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @returns A Zod schema for multi-factor TOTP authentication number form validation.
+ */
export function createMultiFactorTotpAuthNumberFormSchema(ui: FirebaseUI) {
return z.object({
displayName: z.string().min(1, getTranslation(ui, "errors", "displayNameRequired")),
});
}
+/**
+ * Creates a Zod schema for multi-factor TOTP authentication verification form validation.
+ *
+ * Validates that the verification code is exactly 6 characters long.
+ *
+ * @param ui - The FirebaseUI instance.
+ * @returns A Zod schema for multi-factor TOTP authentication verification form validation.
+ */
export function createMultiFactorTotpAuthVerifyFormSchema(ui: FirebaseUI) {
return z.object({
verificationCode: z.string().refine((val) => val.length === 6, {
@@ -102,14 +187,23 @@ export function createMultiFactorTotpAuthVerifyFormSchema(ui: FirebaseUI) {
});
}
+/** The inferred type for the sign-in authentication form schema. */
export type SignInAuthFormSchema = z.infer>;
+/** The inferred type for the sign-up authentication form schema. */
export type SignUpAuthFormSchema = z.infer>;
+/** The inferred type for the forgot password authentication form schema. */
export type ForgotPasswordAuthFormSchema = z.infer>;
+/** The inferred type for the email link authentication form schema. */
export type EmailLinkAuthFormSchema = z.infer>;
+/** The inferred type for the phone authentication number form schema. */
export type PhoneAuthNumberFormSchema = z.infer>;
+/** The inferred type for the phone authentication verification form schema. */
export type PhoneAuthVerifyFormSchema = z.infer>;
+/** The inferred type for the multi-factor phone authentication number form schema. */
export type MultiFactorPhoneAuthNumberFormSchema = z.infer<
ReturnType
>;
+/** The inferred type for the multi-factor TOTP authentication number form schema. */
export type MultiFactorTotpAuthNumberFormSchema = z.infer>;
+/** The inferred type for the multi-factor TOTP authentication verification form schema. */
export type MultiFactorTotpAuthVerifyFormSchema = z.infer>;
diff --git a/packages/core/src/translations.test.ts b/packages/core/src/translations.test.ts
index 3118eb25a..62cd98362 100644
--- a/packages/core/src/translations.test.ts
+++ b/packages/core/src/translations.test.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { describe, expect, it, vi } from "vitest";
// Mock the translations module first
diff --git a/packages/core/src/translations.ts b/packages/core/src/translations.ts
index e2139699e..f8dd6c56f 100644
--- a/packages/core/src/translations.ts
+++ b/packages/core/src/translations.ts
@@ -21,6 +21,20 @@ import {
} from "@invertase/firebaseui-translations";
import { type FirebaseUI } from "./config";
+/**
+ * Gets a translated string for a given category and key.
+ *
+ * Example:
+ * ```typescript
+ * const translation = getTranslation(ui, "errors", "userNotFound");
+ * ```
+ *
+ * @param ui - The FirebaseUI instance.
+ * @param category - The translation category.
+ * @param key - The translation key.
+ * @param replacements - Optional replacements for placeholders.
+ * @returns The translated string.
+ */
export function getTranslation(
ui: FirebaseUI,
category: T,
diff --git a/packages/core/tests/utils.ts b/packages/core/tests/utils.ts
index 948540cac..28b573968 100644
--- a/packages/core/tests/utils.ts
+++ b/packages/core/tests/utils.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { vi } from "vitest";
import type { FirebaseApp } from "firebase/app";
diff --git a/packages/core/vite.config.ts b/packages/core/vite.config.ts
index 8220a98e6..aee7ce7f8 100644
--- a/packages/core/vite.config.ts
+++ b/packages/core/vite.config.ts
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { defineConfig } from "vite";
import path from "node:path";
import { fileURLToPath } from "node:url";
diff --git a/packages/react/src/auth/forms/email-link-auth-form.tsx b/packages/react/src/auth/forms/email-link-auth-form.tsx
index f6b1d03ef..c23bad858 100644
--- a/packages/react/src/auth/forms/email-link-auth-form.tsx
+++ b/packages/react/src/auth/forms/email-link-auth-form.tsx
@@ -28,11 +28,19 @@ import { form } from "~/components/form";
import { Policies } from "~/components/policies";
import { useCallback, useEffect, useState } from "react";
+/** Props for the EmailLinkAuthForm component. */
export type EmailLinkAuthFormProps = {
+ /** Callback function called when the sign-in link email is sent. */
onEmailSent?: () => void;
+ /** Callback function called when sign-in is completed via the email link. */
onSignIn?: (credential: UserCredential) => void;
};
+/**
+ * Creates a memoized action function for sending a sign-in link to an email address.
+ *
+ * @returns A callback function that sends a sign-in link to the specified email address.
+ */
export function useEmailLinkAuthFormAction() {
const ui = useUI();
@@ -53,6 +61,12 @@ export function useEmailLinkAuthFormAction() {
);
}
+/**
+ * Creates a form hook for email link authentication.
+ *
+ * @param onSuccess - Optional callback function called when the sign-in link email is sent.
+ * @returns A form instance configured for email link authentication.
+ */
export function useEmailLinkAuthForm(onSuccess?: EmailLinkAuthFormProps["onEmailSent"]) {
const schema = useEmailLinkAuthFormSchema();
const action = useEmailLinkAuthFormAction();
@@ -75,6 +89,13 @@ export function useEmailLinkAuthForm(onSuccess?: EmailLinkAuthFormProps["onEmail
});
}
+/**
+ * Hook that automatically completes the email link sign-in process when the component mounts.
+ *
+ * Checks if the current URL contains a valid email link sign-in link and completes the authentication.
+ *
+ * @param onSignIn - Optional callback function called when sign-in is completed.
+ */
export function useEmailLinkAuthFormCompleteSignIn(onSignIn?: EmailLinkAuthFormProps["onSignIn"]) {
const ui = useUI();
@@ -91,6 +112,14 @@ export function useEmailLinkAuthFormCompleteSignIn(onSignIn?: EmailLinkAuthFormP
}, [onSignIn]);
}
+/**
+ * A form component for email link authentication.
+ *
+ * Sends a sign-in link to the user's email address and automatically completes sign-in
+ * if the user arrives via an email link.
+ *
+ * @returns The email link auth form component.
+ */
export function EmailLinkAuthForm({ onEmailSent, onSignIn }: EmailLinkAuthFormProps) {
const ui = useUI();
const [emailSent, setEmailSent] = useState(false);
diff --git a/packages/react/src/auth/forms/forgot-password-auth-form.tsx b/packages/react/src/auth/forms/forgot-password-auth-form.tsx
index cd0946110..f6d84a78d 100644
--- a/packages/react/src/auth/forms/forgot-password-auth-form.tsx
+++ b/packages/react/src/auth/forms/forgot-password-auth-form.tsx
@@ -22,11 +22,19 @@ import { form } from "~/components/form";
import { Policies } from "~/components/policies";
import { useCallback, useState } from "react";
+/** Props for the ForgotPasswordAuthForm component. */
export type ForgotPasswordAuthFormProps = {
+ /** Callback function called when the password reset email is sent. */
onPasswordSent?: () => void;
+ /** Callback function called when the back to sign in link is clicked. */
onBackToSignInClick?: () => void;
};
+/**
+ * Creates a memoized action function for sending a password reset email.
+ *
+ * @returns A callback function that sends a password reset email to the specified address.
+ */
export function useForgotPasswordAuthFormAction() {
const ui = useUI();
@@ -47,6 +55,12 @@ export function useForgotPasswordAuthFormAction() {
);
}
+/**
+ * Creates a form hook for forgot password authentication.
+ *
+ * @param onSuccess - Optional callback function called when the password reset email is sent.
+ * @returns A form instance configured for forgot password.
+ */
export function useForgotPasswordAuthForm(onSuccess?: ForgotPasswordAuthFormProps["onPasswordSent"]) {
const schema = useForgotPasswordAuthFormSchema();
const action = useForgotPasswordAuthFormAction();
@@ -69,6 +83,13 @@ export function useForgotPasswordAuthForm(onSuccess?: ForgotPasswordAuthFormProp
});
}
+/**
+ * A form component for requesting a password reset email.
+ *
+ * Displays a success message after the email is sent.
+ *
+ * @returns The forgot password form component.
+ */
export function ForgotPasswordAuthForm({ onBackToSignInClick, onPasswordSent }: ForgotPasswordAuthFormProps) {
const ui = useUI();
const [emailSent, setEmailSent] = useState(false);
diff --git a/packages/react/src/auth/forms/mfa/sms-multi-factor-assertion-form.tsx b/packages/react/src/auth/forms/mfa/sms-multi-factor-assertion-form.tsx
index 28a784339..904cccd3d 100644
--- a/packages/react/src/auth/forms/mfa/sms-multi-factor-assertion-form.tsx
+++ b/packages/react/src/auth/forms/mfa/sms-multi-factor-assertion-form.tsx
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { useCallback, useRef, useState } from "react";
import {
PhoneAuthProvider,
@@ -20,6 +36,11 @@ type PhoneMultiFactorInfo = MultiFactorInfo & {
phoneNumber?: string;
};
+/**
+ * Creates a memoized action function for verifying a phone number during SMS multi-factor assertion.
+ *
+ * @returns A callback function that verifies a phone number using the provided hint and reCAPTCHA verifier.
+ */
export function useSmsMultiFactorAssertionPhoneFormAction() {
const ui = useUI();
@@ -31,12 +52,22 @@ export function useSmsMultiFactorAssertionPhoneFormAction() {
);
}
+/** Options for the SMS multi-factor assertion phone form hook. */
type UseSmsMultiFactorAssertionPhoneForm = {
+ /** The multi-factor info hint containing phone number information. */
hint: MultiFactorInfo;
+ /** The reCAPTCHA verifier instance. */
recaptchaVerifier: RecaptchaVerifier;
+ /** Callback function called when phone verification is successful. */
onSuccess: (verificationId: string) => void;
};
+/**
+ * Creates a form hook for SMS multi-factor assertion phone number verification.
+ *
+ * @param options - The phone form options.
+ * @returns A form instance configured for phone number verification.
+ */
export function useSmsMultiFactorAssertionPhoneForm({
hint,
recaptchaVerifier,
@@ -104,6 +135,11 @@ function SmsMultiFactorAssertionPhoneForm(props: SmsMultiFactorAssertionPhoneFor
);
}
+/**
+ * Creates a memoized action function for verifying the SMS verification code during multi-factor assertion.
+ *
+ * @returns A callback function that verifies the code and signs in with the multi-factor assertion.
+ */
export function useSmsMultiFactorAssertionVerifyFormAction() {
const ui = useUI();
@@ -117,11 +153,20 @@ export function useSmsMultiFactorAssertionVerifyFormAction() {
);
}
+/** Options for the SMS multi-factor assertion verify form hook. */
type UseSmsMultiFactorAssertionVerifyForm = {
+ /** The verification ID from the phone verification step. */
verificationId: string;
+ /** Callback function called when verification is successful. */
onSuccess: (credential: UserCredential) => void;
};
+/**
+ * Creates a form hook for SMS multi-factor assertion verification code input.
+ *
+ * @param options - The verify form options.
+ * @returns A form instance configured for verification code input.
+ */
export function useSmsMultiFactorAssertionVerifyForm({
verificationId,
onSuccess,
@@ -190,11 +235,21 @@ function SmsMultiFactorAssertionVerifyForm(props: SmsMultiFactorAssertionVerifyF
);
}
+/** Props for the SmsMultiFactorAssertionForm component. */
export type SmsMultiFactorAssertionFormProps = {
+ /** The multi-factor info hint containing phone number information. */
hint: MultiFactorInfo;
+ /** Optional callback function called when multi-factor assertion is successful. */
onSuccess?: (credential: UserCredential) => void;
};
+/**
+ * A form component for SMS multi-factor authentication assertion.
+ *
+ * Handles the two-step process: first verifying the phone number, then verifying the SMS code.
+ *
+ * @returns The SMS multi-factor assertion form component.
+ */
export function SmsMultiFactorAssertionForm(props: SmsMultiFactorAssertionFormProps) {
const [verification, setVerification] = useState<{
verificationId: string;
diff --git a/packages/react/src/auth/forms/mfa/sms-multi-factor-enrollment-form.tsx b/packages/react/src/auth/forms/mfa/sms-multi-factor-enrollment-form.tsx
index 7a521d0e3..4c9d5157c 100644
--- a/packages/react/src/auth/forms/mfa/sms-multi-factor-enrollment-form.tsx
+++ b/packages/react/src/auth/forms/mfa/sms-multi-factor-enrollment-form.tsx
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { useCallback, useRef, useState } from "react";
import { multiFactor, PhoneAuthProvider, PhoneMultiFactorGenerator, type RecaptchaVerifier } from "firebase/auth";
import {
@@ -16,6 +32,11 @@ import {
useUI,
} from "~/hooks";
+/**
+ * Creates a memoized action function for verifying a phone number during SMS multi-factor enrollment.
+ *
+ * @returns A callback function that verifies a phone number for MFA enrollment using the provided reCAPTCHA verifier.
+ */
export function useSmsMultiFactorEnrollmentPhoneAuthFormAction() {
const ui = useUI();
@@ -28,12 +49,22 @@ export function useSmsMultiFactorEnrollmentPhoneAuthFormAction() {
);
}
+/** Options for the SMS multi-factor enrollment phone number form hook. */
export type UseSmsMultiFactorEnrollmentPhoneNumberForm = {
+ /** The reCAPTCHA verifier instance. */
recaptchaVerifier: RecaptchaVerifier;
+ /** Callback function called when phone verification is successful. */
onSuccess: (verificationId: string, displayName?: string) => void;
+ /** Optional function to format the phone number before verification. */
formatPhoneNumber?: (phoneNumber: string) => string;
};
+/**
+ * Creates a form hook for SMS multi-factor enrollment phone number verification.
+ *
+ * @param options - The phone number form options.
+ * @returns A form instance configured for phone number input and verification for MFA enrollment.
+ */
export function useSmsMultiFactorEnrollmentPhoneNumberForm({
recaptchaVerifier,
onSuccess,
@@ -115,6 +146,11 @@ function MultiFactorEnrollmentPhoneNumberForm(props: MultiFactorEnrollmentPhoneN
);
}
+/**
+ * Creates a memoized action function for verifying the SMS verification code during multi-factor enrollment.
+ *
+ * @returns A callback function that verifies the code and enrolls the phone number as a multi-factor authentication method.
+ */
export function useMultiFactorEnrollmentVerifyPhoneNumberFormAction() {
const ui = useUI();
return useCallback(
@@ -135,12 +171,22 @@ export function useMultiFactorEnrollmentVerifyPhoneNumberFormAction() {
);
}
+/** Options for the multi-factor enrollment verify phone number form hook. */
type UseMultiFactorEnrollmentVerifyPhoneNumberForm = {
+ /** The verification ID from the phone verification step. */
verificationId: string;
+ /** Optional display name for the enrolled MFA method. */
displayName?: string;
+ /** Callback function called when enrollment is successful. */
onSuccess: () => void;
};
+/**
+ * Creates a form hook for SMS multi-factor enrollment verification code input.
+ *
+ * @param options - The verify phone number form options.
+ * @returns A form instance configured for verification code input during MFA enrollment.
+ */
export function useMultiFactorEnrollmentVerifyPhoneNumberForm({
verificationId,
displayName,
@@ -168,12 +214,21 @@ export function useMultiFactorEnrollmentVerifyPhoneNumberForm({
});
}
+/** Props for the MultiFactorEnrollmentVerifyPhoneNumberForm component. */
type MultiFactorEnrollmentVerifyPhoneNumberFormProps = {
+ /** The verification ID from the phone verification step. */
verificationId: string;
+ /** Optional display name for the enrolled MFA method. */
displayName?: string;
+ /** Callback function called when enrollment is successful. */
onSuccess: () => void;
};
+/**
+ * A form component for verifying the SMS code during multi-factor enrollment.
+ *
+ * @returns The verify phone number form component.
+ */
export function MultiFactorEnrollmentVerifyPhoneNumberForm(props: MultiFactorEnrollmentVerifyPhoneNumberFormProps) {
const ui = useUI();
const form = useMultiFactorEnrollmentVerifyPhoneNumberForm({
@@ -211,10 +266,20 @@ export function MultiFactorEnrollmentVerifyPhoneNumberForm(props: MultiFactorEnr
);
}
+/** Props for the SmsMultiFactorEnrollmentForm component. */
export type SmsMultiFactorEnrollmentFormProps = {
+ /** Optional callback function called when enrollment is successful. */
onSuccess?: () => void;
};
+/**
+ * A form component for SMS multi-factor authentication enrollment.
+ *
+ * Handles the two-step process: first entering the phone number and display name, then verifying the SMS code.
+ *
+ * @returns The SMS multi-factor enrollment form component.
+ * @throws {Error} Throws an error if the user is not authenticated.
+ */
export function SmsMultiFactorEnrollmentForm(props: SmsMultiFactorEnrollmentFormProps) {
const ui = useUI();
diff --git a/packages/react/src/auth/forms/mfa/totp-multi-factor-assertion-form.test.tsx b/packages/react/src/auth/forms/mfa/totp-multi-factor-assertion-form.test.tsx
index a3eb97af6..de7a5d145 100644
--- a/packages/react/src/auth/forms/mfa/totp-multi-factor-assertion-form.test.tsx
+++ b/packages/react/src/auth/forms/mfa/totp-multi-factor-assertion-form.test.tsx
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
/**
* @license
* Copyright 2024 Google LLC
diff --git a/packages/react/src/auth/forms/mfa/totp-multi-factor-assertion-form.tsx b/packages/react/src/auth/forms/mfa/totp-multi-factor-assertion-form.tsx
index 0a69fb230..ad9896982 100644
--- a/packages/react/src/auth/forms/mfa/totp-multi-factor-assertion-form.tsx
+++ b/packages/react/src/auth/forms/mfa/totp-multi-factor-assertion-form.tsx
@@ -1,9 +1,30 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { useCallback } from "react";
import { TotpMultiFactorGenerator, type MultiFactorInfo, type UserCredential } from "firebase/auth";
import { signInWithMultiFactorAssertion, FirebaseUIError, getTranslation } from "@invertase/firebaseui-core";
import { form } from "~/components/form";
import { useMultiFactorTotpAuthVerifyFormSchema, useUI } from "~/hooks";
+/**
+ * Creates a memoized action function for verifying a TOTP code during multi-factor assertion.
+ *
+ * @returns A callback function that verifies the TOTP code and signs in with the multi-factor assertion.
+ */
export function useTotpMultiFactorAssertionFormAction() {
const ui = useUI();
@@ -16,11 +37,20 @@ export function useTotpMultiFactorAssertionFormAction() {
);
}
+/** Options for the TOTP multi-factor assertion form hook. */
export type UseTotpMultiFactorAssertionForm = {
+ /** The multi-factor info hint containing TOTP information. */
hint: MultiFactorInfo;
+ /** Callback function called when verification is successful. */
onSuccess: (credential: UserCredential) => void;
};
+/**
+ * Creates a form hook for TOTP multi-factor assertion verification code input.
+ *
+ * @param options - The TOTP assertion form options.
+ * @returns A form instance configured for TOTP verification code input.
+ */
export function useTotpMultiFactorAssertionForm({ hint, onSuccess }: UseTotpMultiFactorAssertionForm) {
const action = useTotpMultiFactorAssertionFormAction();
const schema = useMultiFactorTotpAuthVerifyFormSchema();
@@ -43,11 +73,21 @@ export function useTotpMultiFactorAssertionForm({ hint, onSuccess }: UseTotpMult
});
}
+/** Props for the TotpMultiFactorAssertionForm component. */
export type TotpMultiFactorAssertionFormProps = {
+ /** The multi-factor info hint containing TOTP information. */
hint: MultiFactorInfo;
+ /** Optional callback function called when multi-factor assertion is successful. */
onSuccess?: (credential: UserCredential) => void;
};
+/**
+ * A form component for TOTP multi-factor authentication assertion.
+ *
+ * Allows users to enter a 6-digit TOTP code from their authenticator app.
+ *
+ * @returns The TOTP multi-factor assertion form component.
+ */
export function TotpMultiFactorAssertionForm(props: TotpMultiFactorAssertionFormProps) {
const ui = useUI();
const form = useTotpMultiFactorAssertionForm({
diff --git a/packages/react/src/auth/forms/mfa/totp-multi-factor-enrollment-form.tsx b/packages/react/src/auth/forms/mfa/totp-multi-factor-enrollment-form.tsx
index ef36fe05e..d800d48d5 100644
--- a/packages/react/src/auth/forms/mfa/totp-multi-factor-enrollment-form.tsx
+++ b/packages/react/src/auth/forms/mfa/totp-multi-factor-enrollment-form.tsx
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { useCallback, useState } from "react";
import { TotpMultiFactorGenerator, type TotpSecret } from "firebase/auth";
import {
@@ -10,6 +26,11 @@ import {
import { form } from "~/components/form";
import { useMultiFactorTotpAuthNumberFormSchema, useMultiFactorTotpAuthVerifyFormSchema, useUI } from "~/hooks";
+/**
+ * Creates a memoized action function for generating a TOTP secret for multi-factor enrollment.
+ *
+ * @returns A callback function that generates a TOTP secret.
+ */
export function useTotpMultiFactorSecretGenerationFormAction() {
const ui = useUI();
@@ -18,10 +39,18 @@ export function useTotpMultiFactorSecretGenerationFormAction() {
}, [ui]);
}
+/** Options for the TOTP multi-factor enrollment form hook. */
export type UseTotpMultiFactorEnrollmentForm = {
+ /** Callback function called when the TOTP secret is generated. */
onSuccess: (secret: TotpSecret, displayName: string) => void;
};
+/**
+ * Creates a form hook for TOTP multi-factor enrollment secret generation.
+ *
+ * @param options - The TOTP enrollment form options.
+ * @returns A form instance configured for display name input and secret generation.
+ */
export function useTotpMultiFactorSecretGenerationForm({ onSuccess }: UseTotpMultiFactorEnrollmentForm) {
const action = useTotpMultiFactorSecretGenerationFormAction();
const schema = useMultiFactorTotpAuthNumberFormSchema();
@@ -78,6 +107,11 @@ function TotpMultiFactorSecretGenerationForm(props: TotpMultiFactorSecretGenerat
);
}
+/**
+ * Creates a memoized action function for verifying the TOTP code during multi-factor enrollment.
+ *
+ * @returns A callback function that verifies the TOTP code and enrolls it as a multi-factor authentication method.
+ */
export function useMultiFactorEnrollmentVerifyTotpFormAction() {
const ui = useUI();
return useCallback(
@@ -97,12 +131,22 @@ export function useMultiFactorEnrollmentVerifyTotpFormAction() {
);
}
+/** Options for the multi-factor enrollment verify TOTP form hook. */
type UseMultiFactorEnrollmentVerifyTotpForm = {
+ /** The TOTP secret generated in the previous step. */
secret: TotpSecret;
+ /** The display name for the enrolled MFA method. */
displayName: string;
+ /** Callback function called when enrollment is successful. */
onSuccess: () => void;
};
+/**
+ * Creates a form hook for TOTP multi-factor enrollment verification code input.
+ *
+ * @param options - The verify TOTP form options.
+ * @returns A form instance configured for TOTP verification code input during MFA enrollment.
+ */
export function useMultiFactorEnrollmentVerifyTotpForm({
secret,
displayName,
@@ -129,12 +173,24 @@ export function useMultiFactorEnrollmentVerifyTotpForm({
});
}
+/** Props for the MultiFactorEnrollmentVerifyTotpForm component. */
type MultiFactorEnrollmentVerifyTotpFormProps = {
+ /** The TOTP secret generated in the previous step. */
secret: TotpSecret;
+ /** The display name for the enrolled MFA method. */
displayName: string;
+ /** Callback function called when enrollment is successful. */
onSuccess: () => void;
};
+/**
+ * A form component for verifying the TOTP code during multi-factor enrollment.
+ *
+ * Displays a QR code and secret key for the user to scan with their authenticator app,
+ * then allows them to verify the enrollment with a TOTP code.
+ *
+ * @returns The verify TOTP form component.
+ */
export function MultiFactorEnrollmentVerifyTotpForm(props: MultiFactorEnrollmentVerifyTotpFormProps) {
const ui = useUI();
const form = useMultiFactorEnrollmentVerifyTotpForm({
@@ -179,10 +235,20 @@ export function MultiFactorEnrollmentVerifyTotpForm(props: MultiFactorEnrollment
);
}
+/** Props for the TotpMultiFactorEnrollmentForm component. */
export type TotpMultiFactorEnrollmentFormProps = {
+ /** Optional callback function called when enrollment is successful. */
onSuccess?: () => void;
};
+/**
+ * A form component for TOTP multi-factor authentication enrollment.
+ *
+ * Handles the two-step process: first generating a TOTP secret and QR code, then verifying the TOTP code.
+ *
+ * @returns The TOTP multi-factor enrollment form component.
+ * @throws {Error} Throws an error if the user is not authenticated.
+ */
export function TotpMultiFactorEnrollmentForm(props: TotpMultiFactorEnrollmentFormProps) {
const ui = useUI();
diff --git a/packages/react/src/auth/forms/multi-factor-auth-assertion-form.tsx b/packages/react/src/auth/forms/multi-factor-auth-assertion-form.tsx
index a06eb79ed..7135f1991 100644
--- a/packages/react/src/auth/forms/multi-factor-auth-assertion-form.tsx
+++ b/packages/react/src/auth/forms/multi-factor-auth-assertion-form.tsx
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import {
PhoneMultiFactorGenerator,
TotpMultiFactorGenerator,
@@ -11,10 +27,17 @@ import { SmsMultiFactorAssertionForm } from "../forms/mfa/sms-multi-factor-asser
import { Button } from "~/components/button";
import { getTranslation } from "@invertase/firebaseui-core";
+/** Props for the MultiFactorAuthAssertionForm component. */
export type MultiFactorAuthAssertionFormProps = {
+ /** Optional callback function called when multi-factor assertion is successful. */
onSuccess?: (credential: UserCredential) => void;
};
+/**
+ * Hook that cleans up the multi-factor resolver when the component unmounts.
+ *
+ * Ensures the resolver is cleared from the UI state to prevent stale state.
+ */
export function useMultiFactorAssertionCleanup() {
const ui = useUI();
@@ -26,6 +49,15 @@ export function useMultiFactorAssertionCleanup() {
}, []);
}
+/**
+ * A form component for multi-factor authentication assertion.
+ *
+ * Displays the appropriate MFA form (SMS or TOTP) based on the available hints.
+ * If only one hint is available, it is automatically selected.
+ *
+ * @returns The multi-factor auth assertion form component.
+ * @throws {Error} Throws an error if no multi-factor resolver is available.
+ */
export function MultiFactorAuthAssertionForm(props: MultiFactorAuthAssertionFormProps) {
const ui = useUI();
const resolver = ui.multiFactorResolver;
diff --git a/packages/react/src/auth/forms/multi-factor-auth-enrollment-form.tsx b/packages/react/src/auth/forms/multi-factor-auth-enrollment-form.tsx
index a3a41ad34..6b9ec9ce2 100644
--- a/packages/react/src/auth/forms/multi-factor-auth-enrollment-form.tsx
+++ b/packages/react/src/auth/forms/multi-factor-auth-enrollment-form.tsx
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { FactorId } from "firebase/auth";
import { getTranslation } from "@invertase/firebaseui-core";
import { type ComponentProps, useState } from "react";
@@ -9,13 +25,25 @@ import { useUI } from "~/hooks";
type Hint = (typeof FactorId)[keyof typeof FactorId];
+/** Props for the MultiFactorAuthEnrollmentForm component. */
export type MultiFactorAuthEnrollmentFormProps = {
+ /** Optional callback function called when enrollment is successful. */
onEnrollment?: () => void;
+ /** Optional array of factor IDs to allow enrollment for. Defaults to TOTP and PHONE. */
hints?: Hint[];
};
const DEFAULT_HINTS = [FactorId.TOTP, FactorId.PHONE] as const;
+/**
+ * A form component for multi-factor authentication enrollment.
+ *
+ * Displays the appropriate MFA enrollment form (SMS or TOTP) based on the provided hints.
+ * If only one hint is provided, it is automatically selected.
+ *
+ * @returns The multi-factor auth enrollment form component.
+ * @throws {Error} Throws an error if no hints are provided or if an unknown hint type is encountered.
+ */
export function MultiFactorAuthEnrollmentForm(props: MultiFactorAuthEnrollmentFormProps) {
const hints = props.hints ?? DEFAULT_HINTS;
diff --git a/packages/react/src/auth/forms/phone-auth-form.tsx b/packages/react/src/auth/forms/phone-auth-form.tsx
index cbaa7032e..b6c29cbc6 100644
--- a/packages/react/src/auth/forms/phone-auth-form.tsx
+++ b/packages/react/src/auth/forms/phone-auth-form.tsx
@@ -30,6 +30,11 @@ import { form } from "~/components/form";
import { Policies } from "~/components/policies";
import { CountrySelector, type CountrySelectorRef } from "~/components/country-selector";
+/**
+ * Creates a memoized action function for verifying a phone number.
+ *
+ * @returns A callback function that verifies a phone number using the provided reCAPTCHA verifier.
+ */
export function usePhoneNumberFormAction() {
const ui = useUI();
@@ -41,12 +46,22 @@ export function usePhoneNumberFormAction() {
);
}
+/** Options for the phone number form hook. */
type UsePhoneNumberForm = {
+ /** The reCAPTCHA verifier instance. */
recaptchaVerifier: RecaptchaVerifier;
+ /** Callback function called when phone verification is successful. */
onSuccess: (verificationId: string) => void;
+ /** Optional function to format the phone number before verification. */
formatPhoneNumber?: (phoneNumber: string) => string;
};
+/**
+ * Creates a form hook for phone number verification.
+ *
+ * @param options - The phone number form options.
+ * @returns A form instance configured for phone number input and verification.
+ */
export function usePhoneNumberForm({ recaptchaVerifier, onSuccess, formatPhoneNumber }: UsePhoneNumberForm) {
const action = usePhoneNumberFormAction();
const schema = usePhoneAuthNumberFormSchema();
@@ -70,10 +85,19 @@ export function usePhoneNumberForm({ recaptchaVerifier, onSuccess, formatPhoneNu
});
}
+/** Props for the PhoneNumberForm component. */
type PhoneNumberFormProps = {
+ /** Callback function called when phone verification is successful. */
onSubmit: (verificationId: string) => void;
};
+/**
+ * A form component for entering and verifying a phone number.
+ *
+ * Includes a country selector and reCAPTCHA verification.
+ *
+ * @returns The phone number form component.
+ */
export function PhoneNumberForm(props: PhoneNumberFormProps) {
const ui = useUI();
const recaptchaContainerRef = useRef(null);
@@ -119,6 +143,11 @@ export function PhoneNumberForm(props: PhoneNumberFormProps) {
);
}
+/**
+ * Creates a memoized action function for verifying a phone verification code.
+ *
+ * @returns A callback function that confirms the phone number using the verification ID and code.
+ */
export function useVerifyPhoneNumberFormAction() {
const ui = useUI();
@@ -130,11 +159,20 @@ export function useVerifyPhoneNumberFormAction() {
);
}
+/** Options for the verify phone number form hook. */
type UseVerifyPhoneNumberForm = {
+ /** The verification ID from the phone verification step. */
verificationId: string;
+ /** Callback function called when verification is successful. */
onSuccess: (credential: UserCredential) => void;
};
+/**
+ * Creates a form hook for phone verification code input.
+ *
+ * @param options - The verify phone number form options.
+ * @returns A form instance configured for verification code input.
+ */
export function useVerifyPhoneNumberForm({ verificationId, onSuccess }: UseVerifyPhoneNumberForm) {
const schema = usePhoneAuthVerifyFormSchema();
const action = useVerifyPhoneNumberFormAction();
@@ -197,10 +235,19 @@ function VerifyPhoneNumberForm(props: VerifyPhoneNumberFormProps) {
);
}
+/** Props for the PhoneAuthForm component. */
export type PhoneAuthFormProps = {
+ /** Optional callback function called when sign-in is successful. */
onSignIn?: (credential: UserCredential) => void;
};
+/**
+ * A form component for phone authentication.
+ *
+ * Handles the two-step process: first entering the phone number, then verifying the SMS code.
+ *
+ * @returns The phone auth form component.
+ */
export function PhoneAuthForm(props: PhoneAuthFormProps) {
const [verificationId, setVerificationId] = useState(null);
diff --git a/packages/react/src/auth/forms/sign-in-auth-form.tsx b/packages/react/src/auth/forms/sign-in-auth-form.tsx
index c5a25ce7c..1812ccfd5 100644
--- a/packages/react/src/auth/forms/sign-in-auth-form.tsx
+++ b/packages/react/src/auth/forms/sign-in-auth-form.tsx
@@ -23,12 +23,21 @@ import { form } from "~/components/form";
import { Policies } from "~/components/policies";
import { useCallback } from "react";
+/** Props for the SignInAuthForm component. */
export type SignInAuthFormProps = {
+ /** Callback function called when sign-in is successful. */
onSignIn?: (credential: UserCredential) => void;
+ /** Callback function called when the forgot password link is clicked. */
onForgotPasswordClick?: () => void;
+ /** Callback function called when the sign up link is clicked. */
onSignUpClick?: () => void;
};
+/**
+ * Creates a memoized action function for signing in with email and password.
+ *
+ * @returns A callback function that signs in a user with email and password.
+ */
export function useSignInAuthFormAction() {
const ui = useUI();
@@ -49,6 +58,12 @@ export function useSignInAuthFormAction() {
);
}
+/**
+ * Creates a form hook for sign-in authentication.
+ *
+ * @param onSuccess - Optional callback function called when sign-in is successful.
+ * @returns A form instance configured for sign-in.
+ */
export function useSignInAuthForm(onSuccess?: SignInAuthFormProps["onSignIn"]) {
const schema = useSignInAuthFormSchema();
const action = useSignInAuthFormAction();
@@ -72,6 +87,11 @@ export function useSignInAuthForm(onSuccess?: SignInAuthFormProps["onSignIn"]) {
});
}
+/**
+ * A form component for signing in with email and password.
+ *
+ * @returns The sign-in form component.
+ */
export function SignInAuthForm({ onSignIn, onForgotPasswordClick, onSignUpClick }: SignInAuthFormProps) {
const ui = useUI();
const form = useSignInAuthForm(onSignIn);
diff --git a/packages/react/src/auth/forms/sign-up-auth-form.tsx b/packages/react/src/auth/forms/sign-up-auth-form.tsx
index 876f19ee2..f40c4e382 100644
--- a/packages/react/src/auth/forms/sign-up-auth-form.tsx
+++ b/packages/react/src/auth/forms/sign-up-auth-form.tsx
@@ -29,16 +29,29 @@ import { Policies } from "~/components/policies";
import { useCallback } from "react";
import { type z } from "zod";
+/**
+ * Checks if the requireDisplayName behavior is enabled.
+ *
+ * @returns True if display name is required, false otherwise.
+ */
export function useRequireDisplayName() {
const ui = useUI();
return hasBehavior(ui, "requireDisplayName");
}
+/** Props for the SignUpAuthForm component. */
export type SignUpAuthFormProps = {
+ /** Callback function called when sign-up is successful. */
onSignUp?: (credential: UserCredential) => void;
+ /** Callback function called when the sign in link is clicked. */
onSignInClick?: () => void;
};
+/**
+ * Creates a memoized action function for signing up with email and password.
+ *
+ * @returns A callback function that creates a new user account with email and password.
+ */
export function useSignUpAuthFormAction() {
const ui = useUI();
@@ -59,6 +72,12 @@ export function useSignUpAuthFormAction() {
);
}
+/**
+ * Creates a form hook for sign-up authentication.
+ *
+ * @param onSuccess - Optional callback function called when sign-up is successful.
+ * @returns A form instance configured for sign-up.
+ */
export function useSignUpAuthForm(onSuccess?: SignUpAuthFormProps["onSignUp"]) {
const schema = useSignUpAuthFormSchema();
const action = useSignUpAuthFormAction();
@@ -84,6 +103,13 @@ export function useSignUpAuthForm(onSuccess?: SignUpAuthFormProps["onSignUp"]) {
});
}
+/**
+ * A form component for signing up with email and password.
+ *
+ * Optionally includes a display name field if the requireDisplayName behavior is enabled.
+ *
+ * @returns The sign-up form component.
+ */
export function SignUpAuthForm({ onSignInClick, onSignUp }: SignUpAuthFormProps) {
const ui = useUI();
const form = useSignUpAuthForm(onSignUp);
diff --git a/packages/react/src/auth/oauth/apple-sign-in-button.tsx b/packages/react/src/auth/oauth/apple-sign-in-button.tsx
index 6d91226d6..18c970d3b 100644
--- a/packages/react/src/auth/oauth/apple-sign-in-button.tsx
+++ b/packages/react/src/auth/oauth/apple-sign-in-button.tsx
@@ -23,12 +23,21 @@ import { OAuthButton } from "./oauth-button";
import AppleSvgLogo from "~/components/logos/apple/Logo";
import { cn } from "~/utils/cn";
+/** Props for the AppleSignInButton component. */
export type AppleSignInButtonProps = {
+ /** Optional OAuth provider instance. Defaults to Apple provider. */
provider?: OAuthProvider;
+ /** Whether to apply themed styling. */
themed?: boolean;
+ /** Callback function called when sign-in is successful. */
onSignIn?: (credential: UserCredential) => void;
};
+/**
+ * A button component for signing in with Apple.
+ *
+ * @returns The Apple sign-in button component.
+ */
export function AppleSignInButton({ provider, ...props }: AppleSignInButtonProps) {
const ui = useUI();
@@ -40,6 +49,11 @@ export function AppleSignInButton({ provider, ...props }: AppleSignInButtonProps
);
}
+/**
+ * The Apple logo SVG component.
+ *
+ * @returns The Apple logo component.
+ */
export function AppleLogo({ className, ...props }: React.SVGProps) {
return ;
}
diff --git a/packages/react/src/auth/oauth/facebook-sign-in-button.tsx b/packages/react/src/auth/oauth/facebook-sign-in-button.tsx
index be4bfc794..6e5d50841 100644
--- a/packages/react/src/auth/oauth/facebook-sign-in-button.tsx
+++ b/packages/react/src/auth/oauth/facebook-sign-in-button.tsx
@@ -23,12 +23,21 @@ import { OAuthButton } from "./oauth-button";
import FacebookSvgLogo from "~/components/logos/facebook/Logo";
import { cn } from "~/utils/cn";
+/** Props for the FacebookSignInButton component. */
export type FacebookSignInButtonProps = {
+ /** Optional OAuth provider instance. Defaults to Facebook provider. */
provider?: FacebookAuthProvider;
+ /** Whether to apply themed styling. */
themed?: boolean;
+ /** Callback function called when sign-in is successful. */
onSignIn?: (credential: UserCredential) => void;
};
+/**
+ * A button component for signing in with Facebook.
+ *
+ * @returns The Facebook sign-in button component.
+ */
export function FacebookSignInButton({ provider, ...props }: FacebookSignInButtonProps) {
const ui = useUI();
@@ -40,6 +49,11 @@ export function FacebookSignInButton({ provider, ...props }: FacebookSignInButto
);
}
+/**
+ * The Facebook logo SVG component.
+ *
+ * @returns The Facebook logo component.
+ */
export function FacebookLogo({ className, ...props }: React.SVGProps) {
return ;
}
diff --git a/packages/react/src/auth/oauth/github-sign-in-button.tsx b/packages/react/src/auth/oauth/github-sign-in-button.tsx
index e9e52206e..41ae37a2a 100644
--- a/packages/react/src/auth/oauth/github-sign-in-button.tsx
+++ b/packages/react/src/auth/oauth/github-sign-in-button.tsx
@@ -23,12 +23,21 @@ import { OAuthButton } from "./oauth-button";
import GitHubSvgLogo from "~/components/logos/github/Logo";
import { cn } from "~/utils/cn";
+/** Props for the GitHubSignInButton component. */
export type GitHubSignInButtonProps = {
+ /** Optional OAuth provider instance. Defaults to GitHub provider. */
provider?: GithubAuthProvider;
+ /** Whether to apply themed styling. */
themed?: boolean;
+ /** Callback function called when sign-in is successful. */
onSignIn?: (credential: UserCredential) => void;
};
+/**
+ * A button component for signing in with GitHub.
+ *
+ * @returns The GitHub sign-in button component.
+ */
export function GitHubSignInButton({ provider, ...props }: GitHubSignInButtonProps) {
const ui = useUI();
@@ -40,6 +49,11 @@ export function GitHubSignInButton({ provider, ...props }: GitHubSignInButtonPro
);
}
+/**
+ * The GitHub logo SVG component.
+ *
+ * @returns The GitHub logo component.
+ */
export function GitHubLogo({ className, ...props }: React.SVGProps) {
return ;
}
diff --git a/packages/react/src/auth/oauth/google-sign-in-button.tsx b/packages/react/src/auth/oauth/google-sign-in-button.tsx
index 4d33ea2d9..37eaa2c51 100644
--- a/packages/react/src/auth/oauth/google-sign-in-button.tsx
+++ b/packages/react/src/auth/oauth/google-sign-in-button.tsx
@@ -23,12 +23,21 @@ import { OAuthButton } from "./oauth-button";
import GoogleSvgLogo from "~/components/logos/google/Logo";
import { cn } from "~/utils/cn";
+/** Props for the GoogleSignInButton component. */
export type GoogleSignInButtonProps = {
+ /** Optional OAuth provider instance. Defaults to Google provider. */
provider?: GoogleAuthProvider;
+ /** Whether to apply themed styling. Can be true, false, or "neutral". */
themed?: boolean | "neutral";
+ /** Callback function called when sign-in is successful. */
onSignIn?: (credential: UserCredential) => void;
};
+/**
+ * A button component for signing in with Google.
+ *
+ * @returns The Google sign-in button component.
+ */
export function GoogleSignInButton({ provider, ...props }: GoogleSignInButtonProps) {
const ui = useUI();
@@ -40,6 +49,11 @@ export function GoogleSignInButton({ provider, ...props }: GoogleSignInButtonPro
);
}
+/**
+ * The Google logo SVG component.
+ *
+ * @returns The Google logo component.
+ */
export function GoogleLogo({ className, ...props }: React.SVGProps) {
return ;
}
diff --git a/packages/react/src/auth/oauth/microsoft-sign-in-button.tsx b/packages/react/src/auth/oauth/microsoft-sign-in-button.tsx
index 2e85ad512..7342a6843 100644
--- a/packages/react/src/auth/oauth/microsoft-sign-in-button.tsx
+++ b/packages/react/src/auth/oauth/microsoft-sign-in-button.tsx
@@ -23,12 +23,21 @@ import { OAuthButton } from "./oauth-button";
import MicrosoftSvgLogo from "~/components/logos/microsoft/Logo";
import { cn } from "~/utils/cn";
+/** Props for the MicrosoftSignInButton component. */
export type MicrosoftSignInButtonProps = {
+ /** Optional OAuth provider instance. Defaults to Microsoft provider. */
provider?: OAuthProvider;
+ /** Whether to apply themed styling. */
themed?: boolean;
+ /** Callback function called when sign-in is successful. */
onSignIn?: (credential: UserCredential) => void;
};
+/**
+ * A button component for signing in with Microsoft.
+ *
+ * @returns The Microsoft sign-in button component.
+ */
export function MicrosoftSignInButton({ provider, ...props }: MicrosoftSignInButtonProps) {
const ui = useUI();
@@ -40,6 +49,11 @@ export function MicrosoftSignInButton({ provider, ...props }: MicrosoftSignInBut
);
}
+/**
+ * The Microsoft logo SVG component.
+ *
+ * @returns The Microsoft logo component.
+ */
export function MicrosoftLogo({ className, ...props }: React.SVGProps) {
return ;
}
diff --git a/packages/react/src/auth/oauth/oauth-button.tsx b/packages/react/src/auth/oauth/oauth-button.tsx
index 82a2c80ea..83427e35d 100644
--- a/packages/react/src/auth/oauth/oauth-button.tsx
+++ b/packages/react/src/auth/oauth/oauth-button.tsx
@@ -23,12 +23,23 @@ import { useCallback, useState } from "react";
import { Button } from "~/components/button";
import { useUI } from "~/hooks";
+/** Props for the OAuthButton component. */
export type OAuthButtonProps = PropsWithChildren<{
+ /** The authentication provider to sign in with. */
provider: AuthProvider;
+ /** Whether to use themed styling for the button. */
themed?: boolean | string;
+ /** Callback function called when sign-in is successful. */
onSignIn?: (credential: UserCredential) => void;
}>;
+/**
+ * Hook for signing in with an OAuth provider.
+ *
+ * @param provider - The authentication provider to sign in with.
+ * @param onSignIn - Optional callback function called when sign-in is successful.
+ * @returns An object containing the error state and a callback function to trigger sign-in.
+ */
export function useSignInWithProvider(provider: AuthProvider, onSignIn?: (credential: UserCredential) => void) {
const ui = useUI();
const [error, setError] = useState(null);
@@ -51,6 +62,11 @@ export function useSignInWithProvider(provider: AuthProvider, onSignIn?: (creden
return { error, callback };
}
+/**
+ * A button component for signing in with an OAuth provider.
+ *
+ * @returns The OAuth button component.
+ */
export function OAuthButton({ provider, children, themed, onSignIn }: OAuthButtonProps) {
const ui = useUI();
diff --git a/packages/react/src/auth/oauth/twitter-sign-in-button.tsx b/packages/react/src/auth/oauth/twitter-sign-in-button.tsx
index 492f43d51..7f14db802 100644
--- a/packages/react/src/auth/oauth/twitter-sign-in-button.tsx
+++ b/packages/react/src/auth/oauth/twitter-sign-in-button.tsx
@@ -23,12 +23,21 @@ import { OAuthButton } from "./oauth-button";
import TwitterSvgLogo from "~/components/logos/twitter/Logo";
import { cn } from "~/utils/cn";
+/** Props for the TwitterSignInButton component. */
export type TwitterSignInButtonProps = {
+ /** Optional OAuth provider instance. Defaults to Twitter provider. */
provider?: TwitterAuthProvider;
+ /** Whether to apply themed styling. */
themed?: boolean;
+ /** Callback function called when sign-in is successful. */
onSignIn?: (credential: UserCredential) => void;
};
+/**
+ * A button component for signing in with Twitter.
+ *
+ * @returns The Twitter sign-in button component.
+ */
export function TwitterSignInButton({ provider, ...props }: TwitterSignInButtonProps) {
const ui = useUI();
@@ -40,6 +49,11 @@ export function TwitterSignInButton({ provider, ...props }: TwitterSignInButtonP
);
}
+/**
+ * The Twitter logo SVG component.
+ *
+ * @returns The Twitter logo component.
+ */
export function TwitterLogo({ className, ...props }: React.SVGProps) {
return ;
}
diff --git a/packages/react/src/auth/screens/email-link-auth-screen.tsx b/packages/react/src/auth/screens/email-link-auth-screen.tsx
index 7072b9c90..268a79988 100644
--- a/packages/react/src/auth/screens/email-link-auth-screen.tsx
+++ b/packages/react/src/auth/screens/email-link-auth-screen.tsx
@@ -24,12 +24,21 @@ import { EmailLinkAuthForm, type EmailLinkAuthFormProps } from "../forms/email-l
import { RedirectError } from "~/components/redirect-error";
import { MultiFactorAuthAssertionScreen } from "./multi-factor-auth-assertion-screen";
+/** Props for the EmailLinkAuthScreen component. */
export type EmailLinkAuthScreenProps = PropsWithChildren<
Pick & {
+ /** Callback function called when sign-in is successful. */
onSignIn?: (user: User) => void;
}
>;
+/**
+ * A screen component for email link authentication.
+ *
+ * Displays a card with the email link auth form and handles multi-factor authentication if required.
+ *
+ * @returns The email link auth screen component.
+ */
export function EmailLinkAuthScreen({ children, onEmailSent, onSignIn }: EmailLinkAuthScreenProps) {
const ui = useUI();
diff --git a/packages/react/src/auth/screens/forgot-password-auth-screen.tsx b/packages/react/src/auth/screens/forgot-password-auth-screen.tsx
index 6dbbe79ba..944fbea12 100644
--- a/packages/react/src/auth/screens/forgot-password-auth-screen.tsx
+++ b/packages/react/src/auth/screens/forgot-password-auth-screen.tsx
@@ -19,8 +19,16 @@ import { useUI } from "~/hooks";
import { Card, CardContent, CardHeader, CardSubtitle, CardTitle } from "../../components/card";
import { ForgotPasswordAuthForm, type ForgotPasswordAuthFormProps } from "../forms/forgot-password-auth-form";
+/** Props for the ForgotPasswordAuthScreen component. */
export type ForgotPasswordAuthScreenProps = ForgotPasswordAuthFormProps;
+/**
+ * A screen component for requesting a password reset.
+ *
+ * Displays a card with the forgot password form.
+ *
+ * @returns The forgot password screen component.
+ */
export function ForgotPasswordAuthScreen(props: ForgotPasswordAuthScreenProps) {
const ui = useUI();
diff --git a/packages/react/src/auth/screens/multi-factor-auth-assertion-screen.tsx b/packages/react/src/auth/screens/multi-factor-auth-assertion-screen.tsx
index 1d6ff4b97..79c5c3e69 100644
--- a/packages/react/src/auth/screens/multi-factor-auth-assertion-screen.tsx
+++ b/packages/react/src/auth/screens/multi-factor-auth-assertion-screen.tsx
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { getTranslation } from "@invertase/firebaseui-core";
import { Card, CardContent, CardHeader, CardSubtitle, CardTitle } from "~/components/card";
import { useUI } from "~/hooks";
@@ -6,8 +22,16 @@ import {
type MultiFactorAuthAssertionFormProps,
} from "../forms/multi-factor-auth-assertion-form";
+/** Props for the MultiFactorAuthAssertionScreen component. */
export type MultiFactorAuthAssertionScreenProps = MultiFactorAuthAssertionFormProps;
+/**
+ * A screen component for multi-factor authentication assertion.
+ *
+ * Displays a card with the multi-factor assertion form.
+ *
+ * @returns The multi-factor auth assertion screen component.
+ */
export function MultiFactorAuthAssertionScreen(props: MultiFactorAuthAssertionScreenProps) {
const ui = useUI();
diff --git a/packages/react/src/auth/screens/multi-factor-auth-enrollment-screen.tsx b/packages/react/src/auth/screens/multi-factor-auth-enrollment-screen.tsx
index 7c4275925..f76716b41 100644
--- a/packages/react/src/auth/screens/multi-factor-auth-enrollment-screen.tsx
+++ b/packages/react/src/auth/screens/multi-factor-auth-enrollment-screen.tsx
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { getTranslation } from "@invertase/firebaseui-core";
import { Card, CardContent, CardHeader, CardSubtitle, CardTitle } from "~/components/card";
import { useUI } from "~/hooks";
@@ -6,8 +22,16 @@ import {
type MultiFactorAuthEnrollmentFormProps,
} from "../forms/multi-factor-auth-enrollment-form";
+/** Props for the MultiFactorAuthEnrollmentScreen component. */
export type MultiFactorAuthEnrollmentScreenProps = MultiFactorAuthEnrollmentFormProps;
+/**
+ * A screen component for multi-factor authentication enrollment.
+ *
+ * Displays a card with the multi-factor enrollment form.
+ *
+ * @returns The multi-factor auth enrollment screen component.
+ */
export function MultiFactorAuthEnrollmentScreen(props: MultiFactorAuthEnrollmentScreenProps) {
const ui = useUI();
diff --git a/packages/react/src/auth/screens/oauth-screen.tsx b/packages/react/src/auth/screens/oauth-screen.tsx
index c3591e370..86d551002 100644
--- a/packages/react/src/auth/screens/oauth-screen.tsx
+++ b/packages/react/src/auth/screens/oauth-screen.tsx
@@ -23,10 +23,20 @@ import { Policies } from "~/components/policies";
import { MultiFactorAuthAssertionScreen } from "./multi-factor-auth-assertion-screen";
import { RedirectError } from "~/components/redirect-error";
+/** Props for the OAuthScreen component. */
export type OAuthScreenProps = PropsWithChildren<{
+ /** Callback function called when sign-in is successful. */
onSignIn?: (user: User) => void;
}>;
+/**
+ * A screen component for OAuth provider authentication.
+ *
+ * Displays a card that should contain OAuth sign-in buttons as children.
+ * Handles multi-factor authentication if required.
+ *
+ * @returns The OAuth screen component.
+ */
export function OAuthScreen({ children, onSignIn }: OAuthScreenProps) {
const ui = useUI();
diff --git a/packages/react/src/auth/screens/phone-auth-screen.tsx b/packages/react/src/auth/screens/phone-auth-screen.tsx
index 53436370b..095e6558b 100644
--- a/packages/react/src/auth/screens/phone-auth-screen.tsx
+++ b/packages/react/src/auth/screens/phone-auth-screen.tsx
@@ -24,10 +24,19 @@ import { MultiFactorAuthAssertionScreen } from "./multi-factor-auth-assertion-sc
import { RedirectError } from "~/components/redirect-error";
import type { User } from "firebase/auth";
+/** Props for the PhoneAuthScreen component. */
export type PhoneAuthScreenProps = PropsWithChildren<{
+ /** Callback function called when sign-in is successful. */
onSignIn?: (user: User) => void;
}>;
+/**
+ * A screen component for phone authentication.
+ *
+ * Displays a card with the phone auth form and handles multi-factor authentication if required.
+ *
+ * @returns The phone auth screen component.
+ */
export function PhoneAuthScreen({ children, ...props }: PhoneAuthScreenProps) {
const ui = useUI();
diff --git a/packages/react/src/auth/screens/sign-in-auth-screen.tsx b/packages/react/src/auth/screens/sign-in-auth-screen.tsx
index 0da74d2ff..a56af1a2d 100644
--- a/packages/react/src/auth/screens/sign-in-auth-screen.tsx
+++ b/packages/react/src/auth/screens/sign-in-auth-screen.tsx
@@ -24,10 +24,19 @@ import { SignInAuthForm, type SignInAuthFormProps } from "../forms/sign-in-auth-
import { MultiFactorAuthAssertionScreen } from "./multi-factor-auth-assertion-screen";
import { RedirectError } from "~/components/redirect-error";
+/** Props for the SignInAuthScreen component. */
export type SignInAuthScreenProps = PropsWithChildren> & {
+ /** Callback function called when sign-in is successful. */
onSignIn?: (user: User) => void;
};
+/**
+ * A screen component for signing in with email and password.
+ *
+ * Displays a card with the sign-in form and handles multi-factor authentication if required.
+ *
+ * @returns The sign-in screen component.
+ */
export function SignInAuthScreen({ children, onSignIn, ...props }: SignInAuthScreenProps) {
const ui = useUI();
diff --git a/packages/react/src/auth/screens/sign-up-auth-screen.tsx b/packages/react/src/auth/screens/sign-up-auth-screen.tsx
index 5dac1981c..09a6115cf 100644
--- a/packages/react/src/auth/screens/sign-up-auth-screen.tsx
+++ b/packages/react/src/auth/screens/sign-up-auth-screen.tsx
@@ -24,10 +24,19 @@ import { getTranslation } from "@invertase/firebaseui-core";
import { RedirectError } from "~/components/redirect-error";
import { MultiFactorAuthAssertionScreen } from "./multi-factor-auth-assertion-screen";
+/** Props for the SignUpAuthScreen component. */
export type SignUpAuthScreenProps = PropsWithChildren> & {
+ /** Callback function called when sign-up is successful. */
onSignUp?: (user: User) => void;
};
+/**
+ * A screen component for signing up with email and password.
+ *
+ * Displays a card with the sign-up form and handles multi-factor authentication if required.
+ *
+ * @returns The sign-up screen component.
+ */
export function SignUpAuthScreen({ children, onSignUp, ...props }: SignUpAuthScreenProps) {
const ui = useUI();
diff --git a/packages/react/src/components/button.tsx b/packages/react/src/components/button.tsx
index b7445c57e..3e6813155 100644
--- a/packages/react/src/components/button.tsx
+++ b/packages/react/src/components/button.tsx
@@ -19,11 +19,19 @@ import { Slot } from "@radix-ui/react-slot";
import { buttonVariant, type ButtonVariant } from "@invertase/firebaseui-styles";
import { cn } from "~/utils/cn";
+/** Props for the Button component. */
export type ButtonProps = ComponentProps<"button"> & {
+ /** The visual variant of the button. */
variant?: ButtonVariant;
+ /** If true, the button will render as a child component using Radix UI's Slot. */
asChild?: boolean;
};
+/**
+ * A customizable button component with multiple variants.
+ *
+ * @returns The button component.
+ */
export function Button({ className, variant = "primary", asChild, ...props }: ButtonProps) {
const Comp = asChild ? Slot : "button";
return ;
diff --git a/packages/react/src/components/card.tsx b/packages/react/src/components/card.tsx
index c382af907..6f485a08e 100644
--- a/packages/react/src/components/card.tsx
+++ b/packages/react/src/components/card.tsx
@@ -17,8 +17,14 @@
import type { ComponentProps, PropsWithChildren } from "react";
import { cn } from "~/utils/cn";
+/** Props for the Card component. */
export type CardProps = PropsWithChildren>;
+/**
+ * A card container component for grouping related content.
+ *
+ * @returns The card component.
+ */
export function Card({ children, className, ...props }: CardProps) {
return (
@@ -27,6 +33,11 @@ export function Card({ children, className, ...props }: CardProps) {
);
}
+/**
+ * The header section of a card.
+ *
+ * @returns The card header component.
+ */
export function CardHeader({ children, className, ...props }: CardProps) {
return (
@@ -35,6 +46,11 @@ export function CardHeader({ children, className, ...props }: CardProps) {
);
}
+/**
+ * The title of a card.
+ *
+ * @returns The card title component.
+ */
export function CardTitle({ children, className, ...props }: ComponentProps<"h2">) {
return (
@@ -43,6 +59,11 @@ export function CardTitle({ children, className, ...props }: ComponentProps<"h2"
);
}
+/**
+ * The subtitle of a card.
+ *
+ * @returns The card subtitle component.
+ */
export function CardSubtitle({ children, className, ...props }: ComponentProps<"p">) {
return (
@@ -51,6 +72,11 @@ export function CardSubtitle({ children, className, ...props }: ComponentProps<"
);
}
+/**
+ * The content section of a card.
+ *
+ * @returns The card content component.
+ */
export function CardContent({ children, className, ...props }: ComponentProps<"div">) {
return (
diff --git a/packages/react/src/components/country-selector.tsx b/packages/react/src/components/country-selector.tsx
index c6c8a85cb..bfa4bfbdc 100644
--- a/packages/react/src/components/country-selector.tsx
+++ b/packages/react/src/components/country-selector.tsx
@@ -21,23 +21,45 @@ import { type ComponentProps, forwardRef, useImperativeHandle, useState, useCall
import { useUI } from "~/hooks";
import { cn } from "~/utils/cn";
+/** Ref methods for the CountrySelector component. */
export interface CountrySelectorRef {
+ /** Gets the currently selected country. */
getCountry: () => CountryData;
+ /** Sets the selected country by country code. */
setCountry: (code: CountryCode) => void;
}
+/** Props for the CountrySelector component. */
export type CountrySelectorProps = ComponentProps<"div">;
+/**
+ * Gets the list of allowed countries from the country codes behavior.
+ *
+ * @returns The list of allowed countries.
+ */
export function useCountries() {
const ui = useUI();
return getBehavior(ui, "countryCodes")().allowedCountries;
}
+/**
+ * Gets the default country from the country codes behavior.
+ *
+ * @returns The default country data.
+ */
export function useDefaultCountry() {
const ui = useUI();
return getBehavior(ui, "countryCodes")().defaultCountry;
}
+/**
+ * A country selector component for phone number input.
+ *
+ * Displays a dropdown with country flags, dial codes, and names for selecting a country.
+ *
+ * @param ref - A ref to access the country selector methods.
+ * @returns The country selector component.
+ */
export const CountrySelector = forwardRef(({ className, ...props }, ref) => {
const countries = useCountries();
const defaultCountry = useDefaultCountry();
diff --git a/packages/react/src/components/divider.tsx b/packages/react/src/components/divider.tsx
index f7258eccc..03f030f07 100644
--- a/packages/react/src/components/divider.tsx
+++ b/packages/react/src/components/divider.tsx
@@ -17,8 +17,14 @@
import { type ComponentProps, type PropsWithChildren } from "react";
import { cn } from "~/utils/cn";
+/** Props for the Divider component. */
export type DividerProps = PropsWithChildren>;
+/**
+ * A divider component that can display a line or a line with text in the middle.
+ *
+ * @returns The divider component.
+ */
export function Divider({ className, children, ...props }: DividerProps) {
if (!children) {
return (
diff --git a/packages/react/src/components/form.test.tsx b/packages/react/src/components/form.test.tsx
index db1557dff..c609c80ae 100644
--- a/packages/react/src/components/form.test.tsx
+++ b/packages/react/src/components/form.test.tsx
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { describe, it, expect, afterEach, vi, beforeEach } from "vitest";
import { render, screen, cleanup, renderHook, act, waitFor } from "@testing-library/react";
import { form } from "./form";
diff --git a/packages/react/src/components/form.tsx b/packages/react/src/components/form.tsx
index a27e9501f..897cf01ee 100644
--- a/packages/react/src/components/form.tsx
+++ b/packages/react/src/components/form.tsx
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import { type ComponentProps, type PropsWithChildren, type ReactNode } from "react";
import { type AnyFieldApi, createFormHook, createFormHookContexts } from "@tanstack/react-form";
import { Button } from "./button";
@@ -91,6 +107,12 @@ function ErrorMessage() {
);
}
+/**
+ * A form hook factory for creating forms with validation and error handling.
+ *
+ * Provides field components (Input) and form components (SubmitButton, ErrorMessage, Action)
+ * for building accessible forms with TanStack Form.
+ */
export const form = createFormHook({
fieldComponents: {
Input,
diff --git a/packages/react/src/components/logos/apple/Logo.tsx b/packages/react/src/components/logos/apple/Logo.tsx
index 844d6c48c..760b9c761 100644
--- a/packages/react/src/components/logos/apple/Logo.tsx
+++ b/packages/react/src/components/logos/apple/Logo.tsx
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
import type { SVGProps } from "react";
const SvgLogo = (props: SVGProps) => (