Skip to content
This repository has been archived by the owner on Apr 12, 2020. It is now read-only.

How to set "active" link? #45

Closed
RedHatter opened this issue Sep 26, 2019 · 12 comments
Closed

How to set "active" link? #45

RedHatter opened this issue Sep 26, 2019 · 12 comments
Labels
enhancement New feature or request

Comments

@RedHatter
Copy link

When writing a menu using svero how can I get the active path to style the menu link with? I could use the router prop if the menu was rendered inside of the route but I would like to avoid that to keep things DRY.

<nav>
  <Link href="/today" class:active={ ??? }>Today</Link>
  <Link href="/planner" class:active={ ??? }>Planner</Link>
  <Link href="/food" class:active={ ??? }>Food</Link>
</nav>

<Router>
  <Route path="/" component={Home} />
  <Route path="/today" component={Today} />
  <Route path="/planner" component={Planner} />
  <Route path="/food" component={Food} />
</Router>

@pateketrueke
Copy link
Contributor

Currently there is no way to do that, do you think it would be easy to open PR fixing this?

@PersonThing
Copy link

Can't you just do class="{shouldBeActive ? 'active' : ''}"

@pateketrueke
Copy link
Contributor

pateketrueke commented Oct 19, 2019

Yeah, I mean, the implementation behind shouldBeActive does not exists... yet, I was asking for feedback on how it would look-like the implementation.

Pushing a PR to solve this would be great, but no activity is seen for a while... 🤔

@kazzkiq
Copy link
Owner

kazzkiq commented Nov 1, 2019

As of today it must be done manually. E.g.

<script>
  import { Link } from 'svero';
  $: path = window.location.pathname;
</script>

<nav>
  <Link href="/today" class:active={path.includes('/today')}>Today</Link>
  <Link href="/planner" class:active={path.includes('/planner')}>Planner</Link>
  <Link href="/food" class:active={path.includes('/food')}>Food</Link>
</nav>

But it's indeed an interesting improvement to have in future versions.

@kazzkiq kazzkiq added the enhancement New feature or request label Nov 1, 2019
@karlitos
Copy link

karlitos commented Dec 4, 2019

As of today it must be done manually. E.g.

<script>
  import { Link } from 'svero';
  $: path = window.location.pathname;
</script>

<nav>
  <Link href="/today" class:active={path.includes('/today')}>Today</Link>
  <Link href="/planner" class:active={path.includes('/planner')}>Planner</Link>
  <Link href="/food" class:active={path.includes('/food')}>Food</Link>
</nav>

But it's indeed an interesting improvement to have in future versions.

I tried that and there it did not work for me. The Link elements are always "active".

There are also some other issues with this. I use svelte-rollup-plugin - basically the svelte starter template and when using the class:active= I get (plugin svelte) ValidationError: Classes can only be applied to DOM elements, not components So I used alternate syntax:

<Link href={MAIN_PATH} className="navbar-nav {path.includes(MAIN_PATH) ? 'active' : ''}">
    Feedback
</Link>

BUT:

my classes defined in the same component (Navbar) and this way they are not included in the bundle, since the RESULTING class looks like .navbar-nav.svelte-1mhbxyw li a.active.svelte-1mhbxyw

@karlitos
Copy link

karlitos commented Dec 5, 2019

So the ValidationError issue is now clarified, so the above code example seems to be invalid.

It should be probably more like:

<script>
  import { Link } from 'svero';
  $: path = window.location.pathname;
</script>

<style>
  :global(a.active) {
    /* ... */
  }
</style

<nav>
  <Link href="/today" class="{path.includes('/today') ? 'active' : ''}">Today</Link>
  <Link href="/planner" class="{path.includes('/planner') ? 'active' : ''}">Planner</Link>
  <Link href="/food" class="{path.includes('/food') ? 'active' : ''}">Food</Link>
</nav>

Which is still not working reactively. 😞

@RedHatter
Copy link
Author

RedHatter commented Dec 5, 2019

Yeah that's the issue. There's no way to watch window.location.pathname directly. Svero would need to notify us when navigation occurred.

@karlitos
Copy link

karlitos commented Dec 5, 2019

It would be much cleaner if sevro would attach some class-name to the active links on its own. See vue-router for reference.

In a meantime I finally managed to find a DIY solution:

<script>
    import { onDestroy } from 'svelte';
    import { Link } from '@c0ldra1n/svero';

    // The patj definitions should be actually globally accessible and shared between the Router and the Navbar
    const MAIN_PATH = '/';
    const ABOUT_PATH = '/about';

    // the current path
    let currentPath = window.location.pathname;
    // handler for changing the current path (when path has changed)
    const setPathOnPathChange = (evt) => {
        currentPath = currentPath !==  evt.target.location.pathname ?  evt.target.location.pathname : currentPath;
    };
    // attach the listener to the 'popstate' events
    window.addEventListener('popstate', setPathOnPathChange);
    // remove the listener in ondestroy lifecycle function to prevent memory leaks ...
    onDestroy(() => window.removeEventListener('popstate', setPathOnPathChange));
</script>

<style>
/* Styles passed with class property (and not with class: directive) has to be declred with :global( ... ) or put in the
global stylesheet, to be included in the bundle.
 */

:global(a.active) {
    color: green !important;
}
</style>

<nav>
  <Link href="/today" className="{path.includes('/today') ? 'active' : ''}">Today</Link>
  <Link href="/planner" className="{path.includes('/planner') ? 'active' : ''}">Planner</Link>
  <Link href="/food" className="{path.includes('/food') ? 'active' : ''}">Food</Link>
</nav>

It works only with className attribute, not class

@pateketrueke
Copy link
Contributor

In yrv I'm adding a [aria-current=page] attribute to achieve this, if you want you can switch to yrv as it maintain the same API as svero. 😉

@karlitos
Copy link

karlitos commented Dec 5, 2019

In yrv I'm adding a [aria-current=page] attribute to achieve this, if you want you can switch to yrv as it maintain the same API as svero. 😉

This is true, switching to yrv was super easy. Also, using the

 a[aria-current="page"] {
  ...
}

selector works, but only if you declare it as a global style :global(.navbar-nav li a[aria-current="page"]) Which is neither yrv issue nor svero issue.

@pateketrueke
Copy link
Contributor

Oh yeah, using the :global(...) selector is often required due svelte semantics.

@kazzkiq
Copy link
Owner

kazzkiq commented Apr 12, 2020

Svero is now deprecated. Check #68 for alternatives.

@kazzkiq kazzkiq closed this as completed Apr 12, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants