Complete workflow for implementing mobile bottom navigation with FAB (Floating Action Button) for Next.js/React applications. Use when creating mobile-responsive navigation with bottom nav bar, FAB menu, active state indicators, and glassmorphism styling. Supports customizable nav items, expandable FAB menus, and proper hydration handling.
Build production-ready mobile bottom navigation with FAB button following modern UI patterns for Next.js and React applications.
The mobile navigation system consists of 3 main parts:
To implement mobile FAB navigation:
assets/MobileBottomNav.tsxnavItems array with your routesfabMenuItems array with secondary actionscomponents/
└── MobileBottomNav.tsx # Main component (copy from assets/)
Copy the template from assets/MobileBottomNav.tsx to your components/ folder.
Edit the navItems array:
const navItems = [
{ href: '/', icon: Home, label: 'Home' },
{ href: '/products', icon: Package, label: 'Products' },
{ href: '/cart', icon: ShoppingCart, label: 'Cart' },
{ href: '/profile', icon: User, label: 'Profile' },
];
Rules:
Edit the fabMenuItems array for secondary navigation:
const fabMenuItems = [
{ href: '/settings', icon: Settings, label: 'Settings' },
{ href: '/help', icon: HelpCircle, label: 'Help' },
{ href: '/about', icon: Info, label: 'About' },
];
In your root layout or app layout:
import MobileBottomNav from '@/components/MobileBottomNav';
export default function Layout({ children }) {
return (
<>
{children}
<MobileBottomNav />
</>
);
}
Add padding to main content to prevent overlap:
<main className="pb-20 lg:pb-0">
{children}
</main>
Default (Purple/Pink):
/* Nav bar gradient */
from-[rgba(78,46,140,0.85)] to-[rgba(108,66,160,0.75)]
/* FAB button */
from-[rgba(217,81,100,1)] to-[rgba(217,81,100,0.8)]
/* Active pill */
bg-[rgba(50,30,90,0.8)]
Blue Theme:
/* Nav bar gradient */
from-[rgba(37,99,235,0.85)] to-[rgba(59,130,246,0.75)]
/* FAB button */
from-[rgba(234,88,12,1)] to-[rgba(234,88,12,0.8)]
/* Active pill */
bg-[rgba(30,58,138,0.8)]
Dark Theme:
/* Nav bar gradient */
from-[rgba(24,24,27,0.95)] to-[rgba(39,39,42,0.9)]
/* FAB button */
from-[rgba(139,92,246,1)] to-[rgba(139,92,246,0.8)]
/* Active pill */
bg-[rgba(63,63,70,0.9)]
Compact (default):
h-10size={16}w-10 h-10Standard:
h-14size={20}w-12 h-12Large:
h-16size={24}w-14 h-14The component handles SSR/hydration properly:
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
setIsMounted(true);
}, []);
if (!isMounted) return null;
Smart path matching for nested routes:
const isActive = (href: string) => {
if (href === '/') return pathname === '/';
return pathname.startsWith(href);
};
Modern glass effect with:
backdrop-blur-xlborder-white/20Desktop hiding with lg:hidden:
<nav className="... lg:hidden z-50">
Built-in ARIA labels:
role="navigation"
aria-label="Mobile navigation"
aria-label="More options"
const navItems = [
{ href: '/', icon: Home, label: 'Home' },
{ href: '/shop', icon: Store, label: 'Shop' },
{ href: '/cart', icon: ShoppingCart, label: 'Cart' },
{ href: '/account', icon: User, label: 'Account' },
];
const fabMenuItems = [
{ href: '/wishlist', icon: Heart, label: 'Wishlist' },
{ href: '/orders', icon: Package, label: 'Orders' },
{ href: '/support', icon: HeadphonesIcon, label: 'Support' },
];
const navItems = [
{ href: '/', icon: Home, label: 'Feed' },
{ href: '/search', icon: Search, label: 'Search' },
{ href: '/notifications', icon: Bell, label: 'Alerts' },
{ href: '/profile', icon: User, label: 'Profile' },
];
const fabMenuItems = [
{ href: '/create', icon: PlusCircle, label: 'Create Post' },
{ href: '/messages', icon: MessageCircle, label: 'Messages' },
{ href: '/settings', icon: Settings, label: 'Settings' },
];
const navItems = [
{ href: '/', icon: Home, label: 'Home' },
{ href: '/articles', icon: FileText, label: 'Articles' },
{ href: '/bookmarks', icon: Bookmark, label: 'Saved' },
{ href: '/profile', icon: User, label: 'Profile' },
];
const fabMenuItems = [
{ href: '/write', icon: Edit, label: 'Write' },
{ href: '/topics', icon: Hash, label: 'Topics' },
{ href: '/about', icon: Info, label: 'About' },
];
const navItems = [
{ href: '/', icon: Home, label: 'Home' },
{ href: '/directory', icon: Users, label: 'Directory' },
{ href: '/gallery', icon: Image, label: 'Gallery' },
{ href: '/contact', icon: Mail, label: 'Contact' },
];
const fabMenuItems = [
{ href: '/about', icon: Info, label: 'About' },
];
Solution: Ensure isMounted check is implemented and returns null during SSR.
Solution: Check z-index values. Nav should be z-50. Ensure no parent has overflow: hidden.
Solution: Add pb-20 (or appropriate padding) to main content container for mobile.
Solution: Ensure backdrop click handler calls setShowMenu(false) and FAB menu has onClick={(e) => e.stopPropagation()}.
Install Lucide if not present:
npm install lucide-react
When implementing pages with mobile FAB navigation, ensure responsive design:
pb-20 lg:pb-0 to main contentcontainer mx-auto px-4 sm:px-6 lg:px-8grid-cols-1 sm:grid-cols-2 lg:grid-cols-3text-sm sm:text-base lg:text-lggap-3 sm:gap-4 lg:gap-6export default function Page() {
return (
<main className="min-h-screen pb-20 lg:pb-0">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 py-6 sm:py-8 lg:py-12">
{/* Hero - responsive height */}
<section className="h-[50vh] sm:h-[60vh] lg:h-[70vh]">
...
</section>
{/* Grid - responsive columns */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6">
{items.map(item => <Card key={item.id} />)}
</div>
</div>
</main>
);
}
Detailed patterns: See references/responsive-layouts.md
assets/MobileBottomNav.tsx - Complete ready-to-use component templatereferences/styling-guide.md - Detailed styling customization optionsreferences/animation-patterns.md - Animation and transition configurationsreferences/responsive-layouts.md - Mobile responsive page layouts and patterns