Reputation: 165
So im currently trying to figure out how I can change the state of a button depending on wether I'm on the page or not.
I have this navbar:
import { Fragment } from 'react'
import { Disclosure, Menu, Transition } from '@headlessui/react'
import { BellIcon, MenuIcon, XIcon } from '@heroicons/react/outline'
import { PlusSmIcon } from '@heroicons/react/solid'
const user = {
name: 'Tom Cook',
email: '[email protected]',
imageUrl:
'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
}
const navigation = [
{ name: 'Home', href: '/', current: true },
{ name: 'Dashboard', href: '/dashboard', current: false },
{ name: 'Price', href: '/price', current: false },
]
const userNavigation = [
{ name: 'Your Profile', href: '/profile' },
{ name: 'Settings', href: '#' },
{ name: 'Sign out', href: '#' },
]
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export default function Navbar() {
return (
<Disclosure as="nav" className="bg-gray-800">
{({ open }) => (
<>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between h-16">
<div className="flex">
<div className="-ml-2 mr-2 flex items-center md:hidden">
{/* Mobile menu button */}
<Disclosure.Button className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white">
<span className="sr-only">Open main menu</span>
{open ? (
<XIcon className="block h-6 w-6" aria-hidden="true" />
) : (
<MenuIcon className="block h-6 w-6" aria-hidden="true" />
)}
</Disclosure.Button>
</div>
<div className="flex-shrink-0 flex items-center">
<img
className="block lg:hidden h-8 w-auto"
src="Assets/img/logo-light.png"
alt="Nemondo"
/>
<img
className="hidden lg:block h-8 w-auto"
src="Assets/img/logo-light.png"
alt="Nemondo"
/>
</div>
<div className="hidden md:ml-6 md:flex md:items-center md:space-x-4">
{navigation.map((item) => (
<a
key={item.name}
href={item.href}
className={classNames(
item.current ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white',
'px-3 py-2 rounded-md text-sm font-medium'
)}
aria-current={item.current ? 'page' : undefined}
>
{item.name}
</a>
))}
</div>
</div>
<div className="flex items-center">
<div className="flex-shrink-0">
<button
type="button"
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-500 hover:bg-indigo-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-800 focus:ring-indigo-500"
>
<PlusSmIcon className="-ml-1 mr-2 h-5 w-5" aria-hidden="true" />
<span>New Job</span>
</button>
</div>
<div className="hidden md:ml-4 md:flex-shrink-0 md:flex md:items-center">
<button
type="button"
className="bg-gray-800 p-1 rounded-full text-gray-400 hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-800 focus:ring-white"
>
<span className="sr-only">View notifications</span>
<BellIcon className="h-6 w-6" aria-hidden="true" />
</button>
{/* Profile dropdown */}
<Menu as="div" className="ml-3 relative">
<div>
<Menu.Button className="bg-gray-800 flex text-sm rounded-full focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-800 focus:ring-white">
<span className="sr-only">Open user menu</span>
<img className="h-8 w-8 rounded-full" src={user.imageUrl} alt="" />
</Menu.Button>
</div>
<Transition
as={Fragment}
enter="transition ease-out duration-200"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items className="origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg py-1 bg-white ring-1 ring-black ring-opacity-5 focus:outline-none z-10">
{userNavigation.map((item) => (
<Menu.Item key={item.name}>
{({ active }) => (
<a
href={item.href}
className={classNames(
active ? 'bg-gray-100' : '',
'block px-4 py-2 text-sm text-gray-700'
)}
>
{item.name}
</a>
)}
</Menu.Item>
))}
</Menu.Items>
</Transition>
</Menu>
</div>
</div>
</div>
</div>
<Disclosure.Panel className="md:hidden">
<div className="px-2 pt-2 pb-3 space-y-1 sm:px-3">
{navigation.map((item) => (
<Disclosure.Button
key={item.name}
as="a"
href={item.href}
className={classNames(
item.current ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white',
'block px-3 py-2 rounded-md text-base font-medium'
)}
aria-current={item.current ? 'page' : undefined}
>
{item.name}
</Disclosure.Button>
))}
</div>
<div className="pt-4 pb-3 border-t border-gray-700">
<div className="flex items-center px-5 sm:px-6">
<div className="flex-shrink-0">
<img className="h-10 w-10 rounded-full" src={user.imageUrl} alt="" />
</div>
<div className="ml-3">
<div className="text-base font-medium text-white">{user.name}</div>
<div className="text-sm font-medium text-gray-400">{user.email}</div>
</div>
<button
type="button"
className="ml-auto flex-shrink-0 bg-gray-800 p-1 rounded-full text-gray-400 hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-800 focus:ring-white"
>
<span className="sr-only">View notifications</span>
<BellIcon className="h-6 w-6" aria-hidden="true" />
</button>
</div>
<div className="mt-3 px-2 space-y-1 sm:px-3">
{userNavigation.map((item) => (
<Disclosure.Button
key={item.name}
as="a"
href={item.href}
className="block px-3 py-2 rounded-md text-base font-medium text-gray-400 hover:text-white hover:bg-gray-700"
>
{item.name}
</Disclosure.Button>
))}
</div>
</div>
</Disclosure.Panel>
</>
)}
</Disclosure>
)
}
It seems that when I change the current:
const navigation = [
{ name: 'Home', href: '/', current: true },
{ name: 'Dashboard', href: '/dashboard', current: false },
{ name: 'Price', href: '/price', current: false },
From true to false and vice versa it does exactly what I need, but how can I make it so it changes depending on whether I'm on the page or not?
Thanks in advance.
Upvotes: 0
Views: 3807
Reputation: 1612
codesandbox: https://codesandbox.io/s/navbar-react-router-dom-v6-p8vy4b
It is not styled very good. The conditional check of current route look like this:
import { useLocation } from "react-router-dom";
const Navbar = () => {
const location = useLocation();
const navigation = [
{
name: "Root",
href: "/"
},
{
name: "Home",
href: "/home"
},
{
name: "About",
href: "/about"
}
];
return (
<navbar
style={{
display: "flex",
height: "50px",
backgroundColor: "red",
width: "100vw"
}}
>
{navigation.map((nav, idx) => {
const isActiveRoute = location.pathname === nav.href;
// const isActiveRoute = location.pathname.startsWith(nav.href) // or if you want a prefix instead
return (
<a
key={idx}
href={nav.href}
style={{ padding: "0 25px", color: isActiveRoute && "black" }}
>
<h3>{nav.name}</h3>
</a>
);
})}
</navbar>
);
};
export default Navbar;
and the routing :
import "./styles.css";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Navbar from "./Navbar";
export default function App() {
const wrapNavbar = (item) => {
return (
<>
<Navbar />
{item}
<p>note: black navbar color is the active item</p>
</>
);
};
return (
<BrowserRouter>
<Routes>
<Route path="/" element={wrapNavbar(<h1>this is root </h1>)} />
<Route path="/home" element={wrapNavbar(<h1>this is home </h1>)} />
<Route path="/about" element={wrapNavbar(<h1>this is about </h1>)} />
</Routes>
</BrowserRouter>
);
}
Upvotes: 1