Welcome to this beginner’s guide to creating a React app using Vite! This tutorial includes a navigation bar, login link, dashboard, and admin section, integrating Basic Authentication with a Node.js Express server at localhost:3000
. The dashboard is for all logged-in users, while the admin section is for “admin” users only. We’ll use plain JavaScript and CSS for simplicity.
What You Need
- Node.js installed (v18.x or later, like v23.10.0 as of June 23, 2025) from nodejs.org.
- A text editor like VS Code.
- Terminal on your Mac.
- Node.js auth server running at
localhost:3000
(see Tutorial: Build a Node.js Server with Basic Authentication Using Express.js.) - Basic JavaScript knowledge (functions and variables).
Set Up the React Project with Vite
Run this command to create a new Vite React app:
npm create vite@latest
Move into the project folder:
cd react-vite-auth
Install the dependencies:
npm install
Start the development server:
npm run dev
Open http://localhost:5173 in your browser to see the default app.
Add React Router
Install React Router for navigation:
npm install react-router-dom
Configure Routing
Replace src/App.jsx
with this code:
import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import Navbar from './Navbar.jsx';
import Dashboard from './Dashboard.jsx';
import Home from './Home.jsx';
import Admin from './Admin.jsx';
import Login from './Login.jsx';
const App = () => {
return (
<Router>
<Navbar />
<div className="content">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/admin" element={<Admin />} />
<Route path="/login" element={<Login />} />
</Routes>
</div>
</Router>
);
};
export default App;
Create src/App.css
for styling:
.content {
max-width: 1200px;
margin: 0 auto;
}
Update src/index.css
for global styling:
:root {
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
color: #213547;
background-color: #ffffff;
}
body {
margin: 0;
min-width: 320px;
min-height: 100vh;
}
a {
color: #646cff;
text-decoration: none;
}
h1 {
font-size: 2em;
}
button {
border-radius: 4px;
border: 1px solid #ccc;
padding: 0.5em 1em;
font-size: 1em;
font-family: inherit;
background-color: #f9f9f9;
cursor: pointer;
}
Create Navigation Bar
Create src/Navbar.jsx
:
import React from 'react';
import { Link} from 'react-router-dom';
import './Navbar.css';
const Navbar = () => {
return (
<nav className="navbar">
<div className="container">
<div className="nav-links nav-links-left">
<Link to="/" className="nav-link">Home</Link>
</div>
<div className="nav-links nav-links-right">
<Link to="/dashboard" className="nav-link">Dashboard</Link>
<Link to="/admin" className="nav-link">Admin</Link>
<Link to="/login" className="nav-link">Login</Link>
</div>
</div>
</nav>
);
};
export default Navbar;
Create src/Navbar.jsx
for styling:
.navbar {
background-color: #333;
}
.container {
max-width: 1200px;
margin: 0 auto;
display: flex;
align-items: center;
position: relative;
}
.nav-links {
display: flex;
}
.nav-links-left {
flex: 1;
display: flex;
justify-content: flex-start;
}
.nav-links-right {
flex: 1;
display: flex;
justify-content: flex-end;
}
.nav-link {
color: white;
text-decoration: none;
padding: 0.5rem 1rem;
}
.nav-link:hover {
color: #ddd;
}
.logout {
background: none;
border: none;
cursor: pointer;
}
Create Pages
Add the following files:
Home.jsx
:
import React from 'react';
const Home = () => {
return <h1 className="title">Welcome to the Home Page</h1>;
};
export default Home;
Login.jsx
:
import React from 'react';
const Login = () => {
return (
<h1>Please provide your credentials</h1>
);
};
export default Login;
Dashboard.jsx
:
import React from 'react';
const Dashboard = () => {
return (
<h1>Welcome to Dashboard</h1>
);
};
export default Dashboard;
Admin.jsx
:
import React from 'react';
const Admin = () => {
return (
<h1>Admin section</h1>
);
};
export default Admin;
Run and Test the App
Start the React app and Node.js server:
- Run
npm run dev
inreact-vite-auth
.
Visit http://localhost:5173: - Test the navigation bar and all the pages

Adding Authentication Logic
Create useAuth.js
:
import { useState, useEffect } from 'react';
const useAuth = () => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [userRole, setUserRole] = useState(null);
useEffect(() => {
const token = localStorage.getItem('authToken');
if (token) {
setIsAuthenticated(true);
const role = localStorage.getItem('userRole') || 'user';
setUserRole(role);
}
}, []);
const login = (username, password) => {
const credentials = btoa(`${username}:${password}`);
fetch('http://localhost:3000/user', {
headers: { 'Authorization': `Basic ${credentials}` },
})
.then(response => {
if (response.ok){
console.log('Login successful');
return response.json();
}
else if (response.status === 401) throw new Error('Invalid credentials');
})
.then(data => {
setIsAuthenticated(true);
setUserRole(data.role);
localStorage.setItem('authToken', credentials);
localStorage.setItem('userRole', data.role);
})
.catch(error => console.error('Login failed:', error));
};
const logout = () => {
setIsAuthenticated(false);
setUserRole(null);
localStorage.removeItem('authToken');
localStorage.removeItem('userRole');
};
return { isAuthenticated, userRole, login, logout };
};
export default useAuth;
Add Proper Login Page
Update Login.jsx
:
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import useAuth from './useAuth';
import './Login.css';
const Login = () => {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const { login } = useAuth();
const navigate = useNavigate();
const handleSubmit = (e) => {
e.preventDefault();
login(username, password);
setTimeout(() => {
navigate('/dashboard');
}, 500); // Wait 0.5s before navigating.
};
return (
<div className="login-container">
<h1 className="title">Login</h1>
<form onSubmit={handleSubmit} className="login-form">
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder="Username"
className="input"
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
className="input"
/>
<button type="submit" className="button">Login</button>
</form>
</div>
);
};
export default Login;
Create Login.css
:
.login-container {
padding: 2rem;
max-width: 400px;
margin: 0 auto;
}
.title {
font-size: 1.5rem;
margin-bottom: 1rem;
}
.login-form {
display: flex;
flex-direction: column;
gap: 1rem;
}
.input {
padding: 0.5rem;
border: 1px solid #ccc;
border-radius: 4px;
}
.button {
padding: 0.5rem;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.button:hover {
background-color: #0056b3;
}
Update Pages to Consider Authentication and Role Status
Update Dashboard.jsx
:
import React from 'react';
import useAuth from './useAuth';
const Dashboard = () => {
const { isAuthenticated, userRole } = useAuth();
if (!isAuthenticated) {
return <p className="message">Please log in to view the dashboard.</p>;
}
return (
<div>
<h1>Dashboard</h1>
<p>Welcome, {userRole}! This is your dashboard.</p>
</div>
);
};
export default Dashboard;
Update Admin.jsx
:
import React from 'react';
import useAuth from './useAuth';
const Admin = () => {
const { isAuthenticated, userRole } = useAuth();
if (!isAuthenticated) {
return <p className="message">Please log in to view the admin section.</p>;
}
if (userRole !== 'admin') {
return <p className="message">Access denied. Admins only.</p>;
}
return (
<div >
<h1>Admin Section</h1>
<p>Welcome, Admin! Manage your settings here.</p>
</div>
);
};
export default Admin;
Implement Logout and Role-sensitive Navbar
Update Navbar.jsx
:
import React from 'react';
import { Link, useNavigate } from 'react-router-dom';
import useAuth from './useAuth';
import './Navbar.css';
const Navbar = () => {
const { isAuthenticated, userRole, logout } = useAuth();
const navigate = useNavigate();
const handleLogout = () => {
logout();
navigate('/');
};
return (
<nav className="navbar">
<div className="container">
<div className="nav-links nav-links-left">
<Link to="/" className="nav-link">Home</Link>
</div>
<div className="nav-links nav-links-right">
{isAuthenticated ? (
<>
<Link to="/dashboard" className="nav-link">Dashboard</Link>
{userRole === 'admin' && (
<Link to="/admin" className="nav-link">Admin</Link>
)}
<button onClick={handleLogout} className="nav-link logout">
Logout
</button>
</>
) : (
<Link to="/login" className="nav-link">Login</Link>
)}
</div>
</div>
</nav>
);
};
export default Navbar;
Run and Test the App
Start the React app and Node.js server:
- Node.js server: Run npm run dev in its directory.
- React app: Run npm run dev in react-vite-auth. Visit http://localhost:5173:
- Click “Login,” enter admin/password123 or user/user123, and submit.
- Navigate to “Dashboard” (for all logged-in users) and “Admin” (for admin only).
Fixing Common Problems
- Login Fails: Check if the Node.js server is running at
localhost:3000
withuserlist.json
. Look at browser console errors (F12 > Console). - Routing Issues: Ensure
react-router-dom
is installed. Try incognito mode or clear cache. - Admin Access Denied: Verify
userRole
is set inuseAuth
after login. - CORS Issues: Confirm the Node.js server allows
http://localhost:5173
.
Wrap Up
You’ve built a React app with Vite using plain JavaScript and CSS, featuring navigation, Basic Authentication, a dashboard, and an admin section! Improve it with token-based auth or more features. Check out Vite documentation and React docs for more.
Happy coding!