@titusjin/universal-header-module
v1.1.1
Published
A comprehensive React universal header component with theme management, sidebar integration, and authentication display
Maintainers
Readme
Universal Header Module
A comprehensive React universal header component for modern web applications with theme management, sidebar integration, user authentication display, and responsive design.
📋 Table of Contents
- Installation
- Quick Start
- Code Structure
- Trigger Points & Integration
- Usage Examples
- API Reference
- Theming & Customization
- Best Practices
- Troubleshooting
Installation
npm install @titusjin/universal-header-moduleQuick Start
import UniversalHeader from '@titusjin/universal-header-module';
import '@titusjin/universal-header-module/dist/styles.css';
function App() {
return <UniversalHeader logoSrc='/your-logo.png' logoAlt='Your Company' />;
}🏗️ Code Structure
module_universalHeader/
├── src/
│ ├── universalHeader.tsx # Main component implementation
│ ├── styles.module.scss # Component styles with CSS modules
│ ├── example.tsx # Example usage component
│ └── index.ts # Module exports
├── dist/ # Built files (auto-generated)
├── package.json # Module dependencies and metadata
├── tsconfig.json # TypeScript configuration
├── rollup.config.js # Build configuration
└── README.md # This documentationComponent Architecture
UniversalHeader
├── Logo Section (Clickable)
├── Navigation Area (Extensible)
├── User Controls
│ ├── Theme Toggle (Dark/Light)
│ ├── User Info Display
│ └── Logout Button
└── Sidebar Toggle (Hamburger Menu)🎯 Trigger Points & Integration
1. Theme Toggle Trigger
- When: User clicks sun/moon icon
- Action: Toggles between light and dark themes
- Persistence: Automatically saves preference to
localStorage - CSS Variables: Updates global CSS custom properties
// Theme toggle automatically handles:
document.documentElement.setAttribute('data-theme', 'dark'); // or 'light'
localStorage.setItem('theme', 'dark');2. Sidebar Integration Trigger
- When: User clicks hamburger menu (☰)
- Action: Calls
sidebarContext.toggleSidebar() - Integration Point: Connect to your sidebar state management
const sidebarContext = {
isSidebarOpen: false,
toggleSidebar: () => setSidebarOpen(!sidebarOpen),
openSidebar: () => setSidebarOpen(true),
closeSidebar: () => setSidebarOpen(false),
};3. Navigation Trigger
- When: User clicks logo or home button
- Action: Calls
onNavigateHome()callback - Integration Point: Connect to your routing system
// Next.js integration
const handleNavigateHome = () => {
router.push('/dashboard');
};
// React Router integration
const handleNavigateHome = () => {
navigate('/');
};4. Authentication Trigger
- When: User clicks logout button
- Action: Calls
onLogout()callback - Integration Point: Connect to your auth system
const handleLogout = async () => {
await authService.logout();
dispatch(clearUserData());
router.push('/login');
};📚 Usage Examples
1. Minimal Setup (No Authentication)
import UniversalHeader from '@titusjin/universal-header-module';
import '@titusjin/universal-header-module/dist/styles.css';
function BasicApp() {
return (
<UniversalHeader
logoSrc='/company-logo.svg'
logoAlt='My Company'
showSidebarToggle={false} // Hide sidebar toggle if no sidebar
/>
);
}2. E-commerce Application Integration
import { useState } from 'react';
import { useRouter } from 'next/navigation';
import UniversalHeader from '@titusjin/universal-header-module';
const EcommerceHeader = () => {
const router = useRouter();
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
// User data from your auth context/store
const user = useUser(); // Your auth hook
const sidebarContext = {
isSidebarOpen,
toggleSidebar: () => setIsSidebarOpen(!isSidebarOpen),
openSidebar: () => setIsSidebarOpen(true),
closeSidebar: () => setIsSidebarOpen(false),
};
const handleLogout = async () => {
await signOut(); // Your auth function
router.push('/login');
};
const handleNavigateHome = () => {
router.push('/dashboard');
};
return (
<>
<UniversalHeader
loginInfo={
user
? {
email: user.email,
name: `${user.firstName} ${user.lastName}`,
role: user.role,
}
: null
}
onLogout={handleLogout}
onNavigateHome={handleNavigateHome}
sidebarContext={sidebarContext}
logoSrc='/store-logo.png'
logoAlt='My Store'
showThemeToggle={true}
showSidebarToggle={true}
className='ecommerce-header'
/>
{/* Your sidebar component */}
{isSidebarOpen && <Sidebar isOpen={isSidebarOpen} onClose={() => setIsSidebarOpen(false)} />}
</>
);
};3. Admin Dashboard Integration
import { logout, selectCurrentUser } from '@/store/authSlice';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { selectSidebarState, toggleSidebar } from '@/store/uiSlice';
const AdminHeader = () => {
const dispatch = useAppDispatch();
const currentUser = useAppSelector(selectCurrentUser);
const { isSidebarOpen } = useAppSelector(selectSidebarState);
const sidebarContext = {
isSidebarOpen,
toggleSidebar: () => dispatch(toggleSidebar()),
openSidebar: () => dispatch(openSidebar()),
closeSidebar: () => dispatch(closeSidebar()),
};
const handleLogout = () => {
dispatch(logout());
};
const handleNavigateHome = () => {
window.location.href = '/admin/dashboard';
};
return (
<UniversalHeader
loginInfo={currentUser}
onLogout={handleLogout}
onNavigateHome={handleNavigateHome}
sidebarContext={sidebarContext}
logoSrc='/admin-logo.png'
logoAlt='Admin Panel'
/>
);
};4. Multi-tenant Application
interface TenantConfig {
logoSrc: string;
logoAlt: string;
themeBrand: string;
}
const MultiTenantHeader = ({ tenantConfig }: { tenantConfig: TenantConfig }) => {
const { user, logout } = useAuth();
const { isSidebarOpen, toggleSidebar } = useSidebar();
// Apply tenant-specific theming
useEffect(() => {
document.documentElement.style.setProperty('--brand-primary', tenantConfig.themeBrand);
}, [tenantConfig.themeBrand]);
return (
<UniversalHeader
loginInfo={user}
onLogout={logout}
onNavigateHome={() => (window.location.href = `/${tenantConfig.slug}/dashboard`)}
sidebarContext={{ isSidebarOpen, toggleSidebar }}
logoSrc={tenantConfig.logoSrc}
logoAlt={tenantConfig.logoAlt}
className={`tenant-${tenantConfig.slug}`}
/>
);
};5. Mobile-First PWA Integration
import { useEffect, useState } from 'react';
const PWAHeader = () => {
const [isMobile, setIsMobile] = useState(false);
const [isOnline, setIsOnline] = useState(navigator.onLine);
useEffect(() => {
const checkMobile = () => setIsMobile(window.innerWidth < 768);
const handleOnlineStatus = () => setIsOnline(navigator.onLine);
checkMobile();
window.addEventListener('resize', checkMobile);
window.addEventListener('online', handleOnlineStatus);
window.addEventListener('offline', handleOnlineStatus);
return () => {
window.removeEventListener('resize', checkMobile);
window.removeEventListener('online', handleOnlineStatus);
window.removeEventListener('offline', handleOnlineStatus);
};
}, []);
return (
<UniversalHeader
logoSrc='/pwa-logo.png'
logoAlt='PWA App'
showSidebarToggle={isMobile}
className={`pwa-header ${!isOnline ? 'offline' : ''}`}
// Additional PWA-specific props
/>
);
};6. Real-time Notifications Integration
import { useNotifications } from '@/hooks/useNotifications';
const NotificationHeader = () => {
const { notifications, markAsRead } = useNotifications();
const unreadCount = notifications.filter((n) => !n.read).length;
return (
<div className='header-with-notifications'>
<UniversalHeader
loginInfo={{ name: 'User', email: '[email protected]' }}
onLogout={handleLogout}
logoSrc='/app-logo.png'
/>
{/* Custom notification bell - extends the header */}
{unreadCount > 0 && (
<div className='notification-badge'>
<span className='badge-count'>{unreadCount}</span>
</div>
)}
</div>
);
};📖 API Reference
UniversalHeaderProps
| Prop | Type | Default | Required | Description |
| ------------------- | -------------------- | -------------------------------- | -------- | ----------------------------------- |
| loginInfo | LoginInfo \| null | null | ✗ | User login information to display |
| onLogout | () => void | undefined | ✗ | Callback when user clicks logout |
| onNavigateHome | () => void | undefined | ✗ | Callback when user clicks logo/home |
| sidebarContext | SidebarContextType | undefined | ✗ | Sidebar state management context |
| logoSrc | string | '/greencitizen-logo-white.png' | ✗ | Logo image source URL |
| logoAlt | string | 'Logo' | ✗ | Logo alt text for accessibility |
| className | string | '' | ✗ | Additional CSS classes |
| showThemeToggle | boolean | true | ✗ | Show/hide theme toggle button |
| showSidebarToggle | boolean | true | ✗ | Show/hide sidebar toggle button |
Type Definitions
LoginInfo
interface LoginInfo {
email?: string; // User's email address
name?: string; // User's display name
avatar?: string; // User's avatar URL
role?: string; // User's role/permission level
[key: string]: any; // Additional user properties
}SidebarContextType
interface SidebarContextType {
isSidebarOpen: boolean; // Current sidebar state
toggleSidebar: () => void; // Toggle sidebar open/closed
openSidebar?: () => void; // Force sidebar open
closeSidebar?: () => void; // Force sidebar closed
}🎨 Theming & Customization
Theme System
The component includes a built-in theme system with automatic persistence:
// Light theme (default)
:root {
--header-bg: #ffffff;
--header-text: #000000;
--header-border: #e5e5e5;
--button-hover: #f5f5f5;
}
// Dark theme
[data-theme='dark'] {
--header-bg: #1a1a1a;
--header-text: #ffffff;
--header-border: #333333;
--button-hover: #2a2a2a;
}CSS Custom Properties Override
/* Custom theme colors */
:root {
--brand-primary: #007bff;
--brand-secondary: #6c757d;
--header-height: 64px;
--header-padding: 1rem;
--logo-max-height: 40px;
--button-border-radius: 0.375rem;
}Custom Styling Examples
Custom Header Styles
.custom-header {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
border-bottom: 3px solid var(--brand-primary);
.logo {
filter: brightness(1.1);
}
.user-info {
background: linear-gradient(45deg, var(--brand-primary), var(--brand-secondary));
color: white;
border-radius: 20px;
}
}Responsive Customization
.mobile-friendly-header {
@media (max-width: 768px) {
.logo {
max-height: 32px;
}
.user-info .name {
display: none; // Hide name on mobile
}
.theme-toggle {
margin-left: 0.5rem;
}
}
}Component Extension
// Extend the header with custom elements
const ExtendedHeader = (props) => (
<div className='extended-header-wrapper'>
<UniversalHeader {...props} />
<div className='header-extensions'>
<SearchBar />
<NotificationBell />
<UserQuickActions />
</div>
</div>
);🚀 Best Practices
1. State Management Integration
// ✅ Good: Integrate with your state management
const Header = () => {
const { user, isAuthenticated } = useAuth();
const { isSidebarOpen, toggleSidebar } = useUI();
return (
<UniversalHeader
loginInfo={isAuthenticated ? user : null}
sidebarContext={{ isSidebarOpen, toggleSidebar }}
onLogout={() => dispatch(logoutUser())}
/>
);
};
// ❌ Bad: Local state for global UI concerns
const Header = () => {
const [user, setUser] = useState(null); // Should be global state
return <UniversalHeader loginInfo={user} />;
};2. Error Handling
// ✅ Good: Handle errors gracefully
const SafeHeader = () => {
const handleLogout = async () => {
try {
await authService.logout();
router.push('/login');
} catch (error) {
toast.error('Logout failed. Please try again.');
console.error('Logout error:', error);
}
};
const handleNavigateHome = () => {
try {
router.push('/dashboard');
} catch (error) {
// Fallback navigation
window.location.href = '/dashboard';
}
};
return <UniversalHeader onLogout={handleLogout} onNavigateHome={handleNavigateHome} />;
};3. Performance Optimization
// ✅ Good: Memoize callbacks and context
const OptimizedHeader = () => {
const sidebarContext = useMemo(
() => ({
isSidebarOpen,
toggleSidebar: () => setIsSidebarOpen(!isSidebarOpen),
}),
[isSidebarOpen]
);
const handleLogout = useCallback(async () => {
await logout();
}, [logout]);
return <UniversalHeader sidebarContext={sidebarContext} onLogout={handleLogout} />;
};4. Accessibility
// ✅ Good: Provide meaningful alt text and ARIA labels
<UniversalHeader
logoSrc='/company-logo.svg'
logoAlt='Acme Corporation - Go to homepage'
loginInfo={{
name: 'John Doe',
email: '[email protected]',
role: 'Administrator',
}}
/>5. Testing Integration
// Test-friendly component setup
const TestableHeader = (props) => (
<UniversalHeader
{...props}
data-testid='universal-header'
logoAlt='Company Logo'
className='testable-header'
/>
);🔧 Troubleshooting
Common Issues
1. Theme Not Persisting
// Problem: Theme resets on page reload
// Solution: Ensure localStorage is available
useEffect(() => {
if (typeof window !== 'undefined') {
const savedTheme = localStorage.getItem('theme');
if (savedTheme) {
document.documentElement.setAttribute('data-theme', savedTheme);
}
}
}, []);2. Sidebar Not Responding
// Problem: Sidebar toggle not working
// Solution: Ensure sidebarContext is properly connected
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
// ✅ Correct context setup
const sidebarContext = {
isSidebarOpen,
toggleSidebar: () => {
console.log('Toggling sidebar:', !isSidebarOpen); // Debug log
setIsSidebarOpen(!isSidebarOpen);
},
};3. Styles Not Loading
// Problem: Styles not applied
// Solution: Import styles in your main app file or layout
import '@titusjin/universal-header-module/dist/styles.css';
// Or in your CSS
@import '@titusjin/universal-header-module/dist/styles.css';4. Logo Not Displaying
// Problem: Logo not showing
// Solution: Check image path and ensure it's accessible
<UniversalHeader
logoSrc='/images/logo.png' // Ensure path is correct
logoAlt='Company Logo' // Always provide alt text
/>5. TypeScript Errors
# Problem: TypeScript can't find module types
# Solution: Install types or add to declarations
npm install @types/react @types/react-dom
# Or create a declarations file
echo 'declare module "@titusjin/universal-header-module";' > src/types/modules.d.tsDebug Mode
Enable debug logging for troubleshooting:
const DebugHeader = () => {
const debugSidebarContext = {
isSidebarOpen,
toggleSidebar: () => {
console.log('🔄 Sidebar toggle clicked. Current state:', isSidebarOpen);
setIsSidebarOpen(!isSidebarOpen);
},
};
return (
<UniversalHeader
sidebarContext={debugSidebarContext}
onLogout={() => console.log('🚪 Logout clicked')}
onNavigateHome={() => console.log('🏠 Home navigation clicked')}
/>
);
};🌟 Features
- 🎨 Built-in Theme System: Automatic dark/light mode with localStorage persistence
- 📱 Responsive Design: Mobile-first approach with breakpoint optimization
- 🍔 Sidebar Integration: Seamless hamburger menu for sidebar control
- 🔐 Authentication Display: User info display with logout functionality
- 🏠 Navigation Support: Clickable logo for home navigation
- 🎛️ Highly Configurable: Extensive props for customization
- 💾 State Persistence: Automatic theme and preference saving
- ♿ Accessibility Ready: ARIA labels and keyboard navigation
- 🚀 Performance Optimized: Minimal re-renders and efficient updates
- 🔧 Developer Friendly: TypeScript support with comprehensive types
📦 Browser Support
| Browser | Version | Notes | | ------------- | ------- | ------------ | | Chrome | 88+ | Full support | | Firefox | 85+ | Full support | | Safari | 14+ | Full support | | Edge | 88+ | Full support | | iOS Safari | 14+ | Full support | | Chrome Mobile | 88+ | Full support |
Legacy Support
For older browsers, include these polyfills:
<!-- For IE11 support -->
<script src="https://polyfill.io/v3/polyfill.min.js?features=default,Array.prototype.find,Promise"></script>📄 License
MIT © Titus Jin
🤝 Contributing
We welcome contributions! Please see our Contributing Guide.
Development Setup
# Clone the repository
git clone https://github.com/titusjin/listingApplication.git
cd listingApplication/module_universalHeader
# Install dependencies
npm install
# Start development
npm run dev
# Build the module
npm run build
# Publish (maintainers only)
npm run publishReporting Issues
When reporting issues, please include:
- 📝 Clear description of the problem
- 🔄 Steps to reproduce
- 🖥️ Browser/environment details
- 📱 Screenshots if applicable
- 🧪 Minimal code example
Made with ❤️ by Titus Jin
