Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

configurable scrollBehavior #12732

Closed
hecateball opened this issue Nov 5, 2021 · 42 comments
Closed

configurable scrollBehavior #12732

hecateball opened this issue Nov 5, 2021 · 42 comments

Comments

@hecateball
Copy link
Contributor

Environment


  • Operating System: Darwin
  • Node Version: v16.11.0
  • Nuxt Version: 3.0.0-27267528.292b524
  • Package Manager: npm@8.0.0
  • Bundler: Vite
  • User Config: buildModules, css, meta
  • Runtime Modules: -
  • Build Modules: nuxt-windicss@^2.0.3

Describe the bug

scrollBehavior setting (which is available in Nuxt2) doesn't work.
I tried both nuxt.config.ts router.scrollBehavior and putting router.scrollBehavior.js in project route but they have no effect.

I couldn't find any document on scrollBehavior at Nuxt3 docs website... Is there any way to make it work?

Reproduction

nuxt.config.ts

import { defineNuxtConfig } from 'nuxt3'

export default defineNuxtConfig({
  // ......
  router: {
    scrollBehavior: () => ({ x: 0, y: 0 }),
  },
})

~/router.scrollBehavior.js

export default () => {
  console.log('here') // never called
  return { x: 0, y: 0 }
}

Additional context

No response

Logs

No response

@danielroe danielroe changed the title scrollBehavior setting doesn't work configurable scrollBehavior Nov 5, 2021
@danielroe
Copy link
Member

You can set this in a plugin:

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.$router.options.scrollBehavior = () => {
    return { left: 0, top: 0 }
  }
})

@hecateball
Copy link
Contributor Author

@danielroe Thank you!
Is that a standard way to configure router in Nuxt 3?

@dergunovs
Copy link

You can set this in a plugin:

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.$router.options.scrollBehavior = () => {
    return { left: 0, top: 0 }
  }
})

This fix works not so smooth. White blink spoils the impression.

@rnotorni
Copy link

I'm sorry.
I have reopened...

@Gyurmatag
Copy link

Gyurmatag commented Feb 19, 2022

The plugin solution is not working smooth. Any idea when will it be fixed?
(first it scrolls up, then it navigates to the page)

@madsh93
Copy link
Sponsor

madsh93 commented Mar 7, 2022

Another thing I noticed is if you add anything with router.push it will scroll to top, even though it may not be what you want to do.

    router.push({
      query: {
        ...route.query,
        equipment: reAddedEquipment.map((x) => x.id)
      }
    })

@danielroe
Copy link
Member

There is a PR in progress: nuxt/framework#3485

@danielroe
Copy link
Member

This is now possible with nuxt/framework#3485. See https://v3.nuxtjs.org/docs/directory-structure/pages#router-options for documentation.

@li9269391
Copy link

This is now possible with nuxt/framework#3485. See https://v3.nuxtjs.org/docs/directory-structure/pages#router-options for documentation.

Configuration has been attempted but not effective. Has anyone succeeded?

@KNTH01
Copy link

KNTH01 commented Apr 20, 2022

Yes @li9269391
Using the recent release candidate:

// app/router.options.js
export default {
  scrollBehavior() {
    return { top: 0 }
  },
}

@Devaiser
Copy link

Devaiser commented Apr 21, 2022

@KevinNTH
Is that all the code that is in this file? It just doesn’t work for me and I don’t quite understand how to properly configure the router.options

@KNTH01
Copy link

KNTH01 commented Apr 22, 2022

@Devaiser yes, that's it for me. I just need to extend the scrollBehavior router option.

nuxt3 version: ^3.0.0-rc.0-27508091.78fcbcf

@TJacoob
Copy link

TJacoob commented Apr 23, 2022

If, like me, you were not able to get this working. The problem was that I was placing the router.options file at the root of the project, instead of the /app folder.

It would be nice to have a full example of this in the docs, as right now the code is spread across issues.

@KNTH01
Copy link

KNTH01 commented Apr 23, 2022

@TJacoob I saw it is actually mentioned in the docs:
image

@Devaiser
Copy link

As already mentioned above, this setting works rather strangely, the page first scrolls up, and only then switches to a new route

@li9269391
Copy link

Yes @li9269391 Using the recent release candidate:

// app/router.options.js
export default {
  scrollBehavior() {
    return { top: 0 }
  },
}

image

It's working

@TJacoob
Copy link

TJacoob commented Apr 27, 2022

@TJacoob I saw it is actually mentioned in the docs

I saw that too but didn't think too much of it. The app folder is not mentioned in the directory structure of the guide, so I wrongly assumed that the app prefix meant the root folder of the app 😅

I understand that the docs are improving as we speak, this is meant to help others that might be making the same mistake I did.

@klyuk88
Copy link

klyuk88 commented Jun 28, 2022

The transition is not smooth, the page flies up, then the transition is made. ((

@tewshi
Copy link
Contributor

tewshi commented Jul 5, 2022

For Nuxt 3 RC 4 that I use,

return { left: 0, top: 0 }

not

return { x: 0, y: 0 }

@jonmes
Copy link

jonmes commented Jul 7, 2022

this might work

no need to configure nuxt.config.ts

/plugins/router.scrollBehaviour.js

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.$router.options.scrollBehavior = async (to, from, savedPosition) => {
    if (savedPosition) {
      return savedPosition;
    }

    const findEl = async (hash, x = 0) => {
      return (
        document.querySelector(hash) ||
        new Promise((resolve) => {
          if (x > 0) {
            return resolve(document.querySelector("#app"));
          }
          setTimeout(() => {
            resolve(findEl(hash, 1));
          }, 100);
        })
      );
    };

    if (to.hash) {
      const el = await findEl(to.hash);

      if ("scrollBehavior" in document.documentElement.style) {
        console.log("hash path hit scroll to");
        // return el.scrollTo({ top: el.offsetTop, behavior: "smooth" });
        return window.scrollTo({ top: el.offsetTop, behavior: "smooth" });
      } else {
        return window.scrollTo(0, el.offsetTop);
      }
    }
    return { left: 0, top: 0, behaviour: "smooth" };
  };
});

@GonzaloHirschToptal
Copy link

this might work

no need to configure nuxt.config.ts

/plugins/router.scrollBehaviour.js

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.$router.options.scrollBehavior = async (to, from, savedPosition) => {
    if (savedPosition) {
      return savedPosition;
    }

    const findEl = async (hash, x = 0) => {
      return (
        document.querySelector(hash) ||
        new Promise((resolve) => {
          if (x > 0) {
            return resolve(document.querySelector("#app"));
          }
          setTimeout(() => {
            resolve(findEl(hash, 1));
          }, 100);
        })
      );
    };

    if (to.hash) {
      const el = await findEl(to.hash);

      if ("scrollBehavior" in document.documentElement.style) {
        console.log("hash path hit scroll to");
        // return el.scrollTo({ top: el.offsetTop, behavior: "smooth" });
        return window.scrollTo({ top: el.offsetTop, behavior: "smooth" });
      } else {
        return window.scrollTo(0, el.offsetTop);
      }
    }
    return { left: 0, top: 0, behaviour: "smooth" };
  };
});

This solution works for me, but I experience an error in the following scenario.

I have a navigation containing links to anchors on a homepage and a single link to a different page. If the homepage was rendered at least once, it works perfectly when navigating from other pages. Now, if i first load any page other than the homepage, when clicking on the nav links to the anchors on the homepage, it fails because the element it tries to find returns null, thus having no offsetTop and causing an exception.

Do I need to configure anything else to account for that?

@GonzaloHirschToptal
Copy link

this might work
no need to configure nuxt.config.ts
/plugins/router.scrollBehaviour.js

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.$router.options.scrollBehavior = async (to, from, savedPosition) => {
    if (savedPosition) {
      return savedPosition;
    }

    const findEl = async (hash, x = 0) => {
      return (
        document.querySelector(hash) ||
        new Promise((resolve) => {
          if (x > 0) {
            return resolve(document.querySelector("#app"));
          }
          setTimeout(() => {
            resolve(findEl(hash, 1));
          }, 100);
        })
      );
    };

    if (to.hash) {
      const el = await findEl(to.hash);

      if ("scrollBehavior" in document.documentElement.style) {
        console.log("hash path hit scroll to");
        // return el.scrollTo({ top: el.offsetTop, behavior: "smooth" });
        return window.scrollTo({ top: el.offsetTop, behavior: "smooth" });
      } else {
        return window.scrollTo(0, el.offsetTop);
      }
    }
    return { left: 0, top: 0, behaviour: "smooth" };
  };
});

This solution works for me, but I experience an error in the following scenario.

I have a navigation containing links to anchors on a homepage and a single link to a different page. If the homepage was rendered at least once, it works perfectly when navigating from other pages. Now, if i first load any page other than the homepage, when clicking on the nav links to the anchors on the homepage, it fails because the element it tries to find returns null, thus having no offsetTop and causing an exception.

Do I need to configure anything else to account for that?

I have just found out that if I increase the timeout from 100 to 300, it gives it enough time so that it can properly find it. Definitely not an elegant solution, but it works for now.

@NaosFr
Copy link

NaosFr commented Aug 2, 2022

Same problem, we need to increase the timeout from 100 to 300 !
Any solutions ?

@jhull
Copy link

jhull commented Sep 10, 2022

I could use the delay too.

The documented approach here: https://nuxtjs.org/docs/configuration-glossary/configuration-router#scrollbehavior did not work for me.

The only thing that worked was the above solution, with naming the file router.options.js placing it in the app directory and then changing to top: 0, left: 0.

But there is still that flash of the current page scrolling up first, really quick, and then it goes to the new page.

@alexanderhorner
Copy link

Yes, please reopen this. The scroll behavior is very jarring. On click it immediately jumps to the top, and then the new page loads.

The correct behavior should be seamless. When the new page renders, it should be scrolled to the correct position.

@danielroe
Copy link
Member

@alexanderhorner This issue is closed because it is implemented (it is configurable). There are several other open issues that describe what you want.

@ricky11
Copy link

ricky11 commented Oct 6, 2022

The nuxt3 docs/guide make no mention of app folder in the structure, and then some where hidden in the docs there is a mention of a app/router.options.js file that needs to be configured. 🤔 One would have to parse github issues to really understand what is going on. Why not in nuxt.config.js under router options?

in vue 2.x all i would need to do in router.js would be :
scrollBehavior(to, from,savedPosition) { return {x:0,y:0} },

this would scroll the next route to the top (like most ssr apps) without any jarring animations or flicker.

The current way mentioned here will scroll to top of the current page and then shift to the next route. (rc11.)

Admittedly this is a Vue router issue, but Nuxt is a "intuitive framework" so lets be a bit more of that.

The only options that worked but still not the way it is 'supposed to be ' is to use a plugin with the page:finish nuxt hook

export default defineNuxtPlugin((nuxtApp) => { nuxtApp.hook('page:finish', () => { window.scrollTo(0, 0); }) })

This will load the next route, and then scroll up (also kinda strange, but better)

Nuxt3 needs a cookbook with solutions for these basic issues.

@ricky11
Copy link

ricky11 commented Oct 7, 2022

This is actually a vue-router issue. But since Nuxt is amazing and <nuxt-link> and generateTo are wrappers of vue Router methods, there should be an "intuitive" way the page UX should route.

If you have solved this issue in nuxt3, please do share your reproduction.. all my tests either have a visible page scroll up before or after the route change.. which is not what most people want.

@Ischafak
Copy link

Ischafak commented Oct 12, 2022

scrollBehavior(to, from,savedPosition) { return {x:0,y:0} }

Hi, i tried this command and it doesnt work. Please
I created a scroll.js inside plugins folder
and my code inside of the file is:

export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.hook("page:finish", () => {
window.scrollTo(0, 0)
})
})

I am changing page with nuxtlink but when i change page scroll stays same position

"nuxt": "3.0.0-rc.11",

@alexanderhorner
Copy link

Do it the official way: like this .

@Ischafak
Copy link

Ischafak commented Oct 12, 2022

@alexanderhorner thank you so much you made my day.
Can i ask you 1 more thing
Even if user try to go same page the scroll goes to top of the page but in nuxt 2 it doesnt go top for same scenario.
Which one is correct and can we make the behaviour something like nuxt 2 in nuxt3?

@aminurislamarnob
Copy link

aminurislamarnob commented Nov 6, 2022

Solution for Nuxt3 (RC):
You need to add this code inside ~/app/router.options.ts file:

import type { RouterOptions } from '@nuxt/schema
export default <RouterOptions> { 
  scrollBehavior(to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition
    } else {
      return { 
        top: 0,
        behavior: 'smooth',
      }
    }
  }
}

@ricky11
Copy link

ricky11 commented Nov 7, 2022

This - scrolls to top BEFORE route navigation, hence its better to remove smooth behaviour here.
This would probably only make sense if your are routing to a # on the same page at the top.

@danielroe danielroe added the 3.x label Jan 19, 2023
@danielroe danielroe transferred this issue from nuxt/framework Jan 19, 2023
@notflip
Copy link

notflip commented Apr 27, 2023

Issue I'm having with this is when I navigate to another page from a link in the footer, the current page first scrolls to the top, then navigates away. @ricky11 As you're saying.

Is there a way to make sure this happens after the route change?

@alexanderhorner
Copy link

alexanderhorner commented Apr 27, 2023

Update to the newest version. Delete any scrollBehavior config. The new default behavior works as expected.

@notflip
Copy link

notflip commented Apr 28, 2023

@alexanderhorner The only thing missing now is smooth scroll behaviour for anchor tags, do you know what needs to be edited in the router.options.ts file, to achieve this? Without breaking default page behaviour

@lazercaveman
Copy link
Contributor

Have a look here: #22663

@wadclapp
Copy link

adding app/router.options.js to my project didn't work until I restarted dev (maybe this info will help someone)

@alexanderhorner
Copy link

This isn't necessary anymore. Delete your routers option file and update to the newest version of nuxt.

@mbyrne00
Copy link

mbyrne00 commented Sep 12, 2023

@alexanderhorner - can you please clarify what you meant by "This isn't necessary any more" and about deleting the options file? If we want to customise router options, we still supply that app/router.options.js file right? Or is the new default behaviour in nuxt3 always scrolling to the top on route change?

@alexanderhorner
Copy link

alexanderhorner commented Sep 13, 2023

Sorry, I assumed this was to fix an older issue where nuxt didn't scroll to the top of the page on navigation. The default behavior is now smarter than most work arounds using this config.

If you still want to customize the scroll behavior, this is of course valid.

Edit to clarify: The default behavior is to scroll to the top of the page upon navigation, except when a position is saved (on navigating backwards for example). Probably best not to mess with that unless you have a good reason for it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests