Skip to content

feat: added react example #25

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions examples/react/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
12 changes: 12 additions & 0 deletions examples/react/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# React + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh

## Expanding the ESLint configuration

If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
33 changes: 33 additions & 0 deletions examples/react/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'

export default [
{ ignores: ['dist'] },
{
files: ['**/*.{js,jsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
ecmaVersion: 'latest',
ecmaFeatures: { jsx: true },
sourceType: 'module',
},
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...js.configs.recommended.rules,
...reactHooks.configs.recommended.rules,
'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
]
14 changes: 14 additions & 0 deletions examples/react/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
<link rel="stylesheet" href="src/index.css">
</body>
</html>
30 changes: 30 additions & 0 deletions examples/react/lib/components/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use client';

import { NavLink } from "react-router";
import { useUser } from "../firebase/hooks";
import { signOut, type User } from "firebase/auth";
import { auth } from "../firebase/clientApp";

export function Header() {
const user = useUser();

async function onSignOut() {
await signOut(auth);
router.push("/sign-in");
}

return (
<header className="border-b border-gray-200">
<div className="max-w-6xl mx-auto h-12 flex items-center">
<div className="font-bold">
<NavLink to="/">FirebaseUI</NavLink>
</div>
<div className="flex-grow flex items-center justify-end">
<ul className="text-sm flex items-center gap-6 *:hover:opacity-75">
{user ? <li><button onClick={onSignOut}>Sign Out</button></li> : <li><NavLink to="/sign-in">Sign In</NavLink></li>}
</ul>
</div>
</div>
</header>
);
}
34 changes: 34 additions & 0 deletions examples/react/lib/firebase/clientApp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"use client";

import { initializeApp, getApps } from "firebase/app";
import { firebaseConfig } from "./config";
import { connectAuthEmulator, getAuth } from "firebase/auth";
import { autoAnonymousLogin, initializeUI } from "@firebase-ui/core";
import { customLanguage, english } from "@firebase-ui/translations";

export const firebaseApp =
getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];

export const auth = getAuth(firebaseApp);

export const ui = initializeUI({
app: firebaseApp,
behaviors: [autoAnonymousLogin()],
translations: [
customLanguage(english.locale, {
labels: {
signIn: "Sign In",
},
prompts: {
signInToAccount: "Sign in to your account",
},
errors: {
invalidEmail: "Please enter a valid email address",
},
}),
],
});

if (import.meta.env.MODE === "development") {
connectAuthEmulator(auth, "http://localhost:9099");
}
11 changes: 11 additions & 0 deletions examples/react/lib/firebase/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const firebaseConfig = {
apiKey: "AIzaSyAotbJXqnZxg9aAsULFn8MLwp_twtMUl2k",
authDomain: "ff-test-74aeb.firebaseapp.com",
databaseURL:
"https://ff-test-74aeb-default-rtdb.asia-southeast1.firebasedatabase.app",
projectId: "ff-test-74aeb",
storageBucket: "ff-test-74aeb.appspot.com",
messagingSenderId: "950537677105",
appId: "1:950537677105:web:da72ccc1718279f3cde810",
measurementId: "G-B5Y2YD83TJ",
};
17 changes: 17 additions & 0 deletions examples/react/lib/firebase/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useState } from "react";

import { onAuthStateChanged } from "firebase/auth";
import { User } from "firebase/auth";
import { useEffect } from "react";
import { auth } from "./clientApp";

export function useUser(initalUser?: User | null) {
const [user, setUser] = useState<User | null>(initalUser ?? null);

useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, setUser);
return () => unsubscribe();
}, []);

return user;
}
22 changes: 22 additions & 0 deletions examples/react/lib/firebase/ui.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"use client";

import { ui } from "./clientApp";
import { ConfigProvider } from "@firebase-ui/react";

export function FirebaseUIProvider({
children,
}: {
children: React.ReactNode;
}) {
return (
<ConfigProvider
ui={ui}
policies={{
termsOfServiceUrl: "https://www.google.com",
privacyPolicyUrl: "https://www.google.com",
}}
>
{children}
</ConfigProvider>
);
}
35 changes: 35 additions & 0 deletions examples/react/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "react",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@firebase-ui/core": "workspace:*",
"@firebase-ui/react": "workspace:*",
"@firebase-ui/styles": "workspace:*",
"@firebase-ui/translations": "workspace:*",
"firebase": "^11.6.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-router": "^7.5.1"
},
"devDependencies": {
"@tailwindcss/vite": "^4.1.4",
"@eslint/js": "^9.22.0",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"@vitejs/plugin-react": "^4.3.4",
"eslint": "^9.22.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.19",
"globals": "^16.0.0",
"vite": "^6.3.1",
"tailwindcss": "^4.1.4"
}
}
1 change: 1 addition & 0 deletions examples/react/public/vite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file added examples/react/src/App.css
Empty file.
110 changes: 110 additions & 0 deletions examples/react/src/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { NavLink } from "react-router";
import { useUser } from "../lib/firebase/hooks";

function App() {
const user = useUser();

return (
<div className="p-8 ">
<h1 className="text-3xl font-bold mb-6">Firebase UI Demo</h1>
<div className="mb-6">
{user && <div>Welcome: {user.email || user.phoneNumber}</div>}
</div>
<div>
<h2 className="text-2xl font-bold mb-4">Auth Screens</h2>
<ul className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
<li>
<NavLink
to="/screens/sign-in-auth-screen"
className="text-blue-500 hover:underline"
>
Sign In Auth Screen
</NavLink>
</li>
<li>
<NavLink
to="/screens/sign-in-auth-screen-w-handlers"
className="text-blue-500 hover:underline"
>
Sign In Auth Screen with Handlers
</NavLink>
</li>
<li>
<NavLink
to="/screens/sign-in-auth-screen-w-oauth"
className="text-blue-500 hover:underline"
>
Sign In Auth Screen with OAuth
</NavLink>
</li>
<li>
<NavLink
to="/screens/email-link-auth-screen"
className="text-blue-500 hover:underline"
>
Email Link Auth Screen
</NavLink>
</li>
<li>
<NavLink
to="/screens/email-link-auth-screen-w-oauth"
className="text-blue-500 hover:underline"
>
Email Link Auth Screen with OAuth
</NavLink>
</li>
<li>
<NavLink
to="/screens/phone-auth-screen"
className="text-blue-500 hover:underline"
>
Phone Auth Screen
</NavLink>
</li>
<li>
<NavLink
to="/screens/phone-auth-screen-w-oauth"
className="text-blue-500 hover:underline"
>
Phone Auth Screen with OAuth
</NavLink>
</li>
<li>
<NavLink
to="/screens/sign-up-auth-screen"
className="text-blue-500 hover:underline"
>
Sign Up Auth Screen
</NavLink>
</li>
<li>
<NavLink
to="/screens/sign-up-auth-screen-w-oauth"
className="text-blue-500 hover:underline"
>
Sign Up Auth Screen with OAuth
</NavLink>
</li>
<li>
<NavLink
to="/screens/oauth-screen"
className="text-blue-500 hover:underline"
>
OAuth Screen
</NavLink>
</li>
<li>
<NavLink
to="/screens/password-reset-screen"
className="text-blue-500 hover:underline"
>
Password Reset Screen
</NavLink>
</li>
</ul>
</div>
</div>
);
}

export default App;
1 change: 1 addition & 0 deletions examples/react/src/assets/react.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions examples/react/src/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import "tailwindcss";
@import "@firebase-ui/styles/src/base.css";

/* @import "@firebase-ui/styles/src/themes/dark.css"; */
/* @import "@firebase-ui/styles/src/themes/brutalist.css"; */
Loading