Logo

Voxlet UI

Tube Light Navbar

A sleek, interactive navigation bar with a dynamic lighting effect, perfect for modern UIs.

The Navbar will show at top of the page

Installation

  1. 1

    Install Dependencies

    npm i framer-motion lucide-react
  2. 2

    lib/utils.ts

    import { clsx, type ClassValue } from "clsx"
    import { twMerge } from "tailwind-merge"
        
    export function cn(...inputs: ClassValue[]) {
      return twMerge(clsx(inputs))
    }
  3. 3

    Copy the source code

    @/components/ui/tubelight-navbar.tsx
    "use client"
    
    import React, { useEffect, useState } from "react"
    import { motion } from "framer-motion"
    import Link from "next/link"
    import { LucideIcon } from "lucide-react"
    import { cn } from "@/lib/utils"
    
    interface NavItem {
        name: string
        url: string
        icon: LucideIcon
    }
    
    interface NavBarProps {
        items: NavItem[]
        className?: string
    }
    
    export function NavBar({ items, className }: NavBarProps) {
        const [activeTab, setActiveTab] = useState(items[0].name)
        const [isMobile, setIsMobile] = useState(false)
    
        useEffect(() => {
            const handleResize = () => {
                setIsMobile(window.innerWidth < 768)
            }
    
            handleResize()
            window.addEventListener("resize", handleResize)
            return () => window.removeEventListener("resize", handleResize)
        }, [])
    
        return (
            <div
                className={cn(
                    "fixed bottom-0 sm:top-0 left-1/2 -translate-x-1/2 z-[200] mb-6 sm:pt-6 h-max",
                    className,
                )}
            >
                <div className="flex items-center gap-3 bg-background/5 border border-border backdrop-blur-lg py-1 px-1 rounded-full shadow-lg">
                    {items.map((item) => {
                        const Icon = item.icon
                        const isActive = activeTab === item.name
    
                        return (
                            <Link
                                key={item.name}
                                href={item.url}
                                onClick={() => setActiveTab(item.name)}
                                className={cn(
                                    "relative cursor-pointer text-sm font-semibold px-6 py-2 rounded-full transition-colors",
                                    "text-foreground/80 hover:text-primary",
                                    isActive && "bg-muted text-primary",
                                )}
                            >
                                <span className="hidden md:inline">{item.name}</span>
                                <span className="md:hidden">
                                    <Icon size={18} strokeWidth={2.5} />
                                </span>
                                {isActive && (
                                    <motion.div
                                        layoutId="lamp"
                                        className="absolute inset-0 w-full bg-primary/5 rounded-full -z-10"
                                        initial={false}
                                        transition={{
                                            type: "spring",
                                            stiffness: 300,
                                            damping: 30,
                                        }}
                                    >
                                        <div className="absolute -top-2 left-1/2 -translate-x-1/2 w-8 h-1 bg-primary rounded-t-full">
                                            <div className="absolute w-12 h-6 bg-primary/20 rounded-full blur-md -top-2 -left-2" />
                                            <div className="absolute w-8 h-6 bg-primary/20 rounded-full blur-md -top-1" />
                                            <div className="absolute w-4 h-4 bg-primary/20 rounded-full blur-sm top-0 left-2" />
                                        </div>
                                    </motion.div>
                                )}
                            </Link>
                        )
                    })}
                </div>
            </div>
        )
    }
    

Props

NavBarProps

PropTypeDefaultDescription
classNamestringundefinedOptional custom class names for styling.
itemsNavItem[][]An array of navigation items containing name, URL, and icon.

NavItem

PropTypeDefaultDescription
namestringundefinedThe label for the navigation item.
urlstringundefinedThe destination URL for the navigation item.
iconLucideIconundefinedThe icon representing the navigation item.

The inspiration for this component is directly taken from Serenity UI

Brought to you by Voxlet