Reputation: 333
I'm working on a sveltekit app with a sidenav containing links. I can't get the active class styling on my links to work properly.
The links are components in NavLink.svelte:
<script>
import { page } from '$app/stores';
import Icon from '$lib/Icon.svelte';
export let title;
export let href;
</script>
<a {href} class="link" class:active={$page.path == href}>
<Icon {title} />
</a>
<style>
a.active {
background-color: rgba(0,0,0,0.24);
</style>
These links are used in SideNav.svelte:
<script>
import NavLink from '$lib/NavLink.svelte';
</script>
<nav class="container">
<div id="links">
<NavLink href="/link1" title="icon1" />
<NavLink href="/link2" title="icon2" />
<NavLink href="/link3" title="icon3" />
</div>
</nav>
And finally, the sidenav is loaded in my __layout.svelte:
<SideNav />
<slot />
<Footer />
Now when I click one of my sidenav links, I am routed to the proper page but my NavLink is not styled with the .active
class. If I inspect the link, however, devtools shows me this: <a class="link active:true">
and the other links have active:false
.
So it looks like the function is working, but my active style is not applied (the background color). What am I missing?
I tried moving the Active class code to the SideNav component instead of the NavLink component and observed the same behavior. I could not figure it out, so I found a new method that works just fine.
In my NavLink.svelte:
<script>
import {onMount} from "svelte";
import Icon from '$lib/Icon.svelte';
let currentPath;
onMount(() => {
currentPath = window.location.pathname;
});
export let title;
export let href;
</script>
<a {href} class:active={currentPath == href}>
<Icon {title} />
</a>
And the rest of the code is the same. Now my links get the proper styling. It's worth noting that they simply have <a class="active">
and not <a class="active:true">
. Why wasn't it working with the other method?
Upvotes: 12
Views: 14954
Reputation: 11
After trying all of these without any luck, I added an !important rule to the css property I was targeting.
The issue came from using a parent .navbar class to select child links, which I guess has a higher specificity (and renders later) than the non-nested .active class. Styling the link elements directly fixed the issue. e.g:
from
.navbar > a {
color: white;
}
.active {
color: blue;
}
to
a {
color: white;
}
.active {
color: blue;
}
I'm not sure how obvious this is to other people, but I'm like 99% sure I've used the exact same pattern (.class > element) + .active
several other times without issue?
Upvotes: 1
Reputation: 1354
This is the approach that I use frequently using $page
store.
First, I structure the navigation data in following format:
item = [{ link: '/hello/world/about', title: 'About }, ...]
Then, I compare current URL's path ($page.url.pathname
) with the file path (item.link
)
<a href={item.link} class:active={$page.url.pathname === item.link}>{item.title}</a>
Alternatively, we can also create a generic method for the same:
export function isActive(page: Page<Record<string, string>>, path: string) {
const pathname = page.url.pathname;
return pathname === path;
}
and use that as:
<a href={item.link} class:active={isActive($page, item.link)}>{item.title}</a>
Upvotes: 0
Reputation: 62
You might want to use $page.route.id
which contains the route id only, even if you have params in the path.
Example, the path /catalogue/123
will gives:
$page.url.pathname
=== /catalogue/123
(different for each item, does not work everywhere)$page.route.id
=== /catalogue/[id]
(same for all items)Then you can use in your links:
<a href="/catalogue/123" class:active={$page.route.id === '/catalogue/[id]'}>catalogue</a>
Inn the end this will work for static links (/catalogue) and dynamic links (/catalogue/456).
Upvotes: 1
Reputation: 363
Here is my solution to only match the first segment of the current URL:
<a
class:active={$page.url.pathname.split("/")[1] ===item.href.split("/")[1]}
href={item.href}>
{item.label}
</a>
a.active {
background-color:red;
}
Upvotes: 0
Reputation: 325
To achieve this in the latest version of SvelteKit, after the introduction of some breaking changes, you can do:
<a {href} class:active={$page.url.pathname === href}>
$page.url
returns something like:
URL {
href: "http://localhost:5173/accounts/login",
origin: "http://localhost:5173",
protocol: "HTTP:",
username: "",
password: "",
host: "localhost:5173",
hostname: "localhost",
port: "5173",
pathname: "/accounts/login",
search: ""
}
You can then compare $page.url.pathname
with the href
of the anchor tag.
Upvotes: 12
Reputation: 333
I figured it out.... I think I just forgot to include quotes. D'oh. Working code (that also accounts for sub-pages) for the NavLink is:
<a {href} class:active="{$page.path.includes(href)}">
Upvotes: 16