Vue3 Smooth Scroll

0.8.1 · active · verified Sun Apr 19

vue3-smooth-scroll is a lightweight, actively maintained Vue 3 plugin dedicated to facilitating smooth scrolling experiences within web applications. It provides two primary methods for implementation: a declarative directive (`v-smooth-scroll`) that can be applied directly to anchor tags, and a more flexible programmatic API accessible through `this.$smoothScroll` in the Options API or `inject('smoothScroll')` within the Composition API. The plugin's design prioritizes Vue 3 compatibility, including robust Server-Side Rendering (SSR) support, which was recently improved in version 0.8.1 to address `window is not defined` errors. It uses `requestAnimationFrame` for efficient, non-blocking animations, with a graceful fallback for broader compatibility across different browser environments. Key features include Y-axis scrolling, the ability to define specific scroll containers, configurable animation duration, offset, and custom easing functions, providing a high degree of customization for scroll behavior. Its small bundle size (approximately 1.4kB gzipped) makes it a performant choice, offering significantly more advanced control and a programmatic interface compared to the native `scroll-behavior` CSS property, especially for intricate scrolling requirements or dynamic content. Releases appear to be driven by bug fixes and compatibility updates rather than a strict schedule, with 0.8.1 being the current stable version.

Common errors

Warnings

Install

Imports

Quickstart

This example demonstrates both directive-based (`v-smooth-scroll`) and programmatic (`inject('smoothScroll')`) smooth scrolling, including usage with custom scroll containers and global/local options for duration and offset.

import { createApp, ref, inject } from 'vue';
import VueSmoothScroll from 'vue3-smooth-scroll';

const App = {
  template: `
    <div id="main-content">
      <h1>Vue3 Smooth Scroll Example</h1>
      <nav>
        <a href="#section1" v-smooth-scroll="{ duration: 800, offset: -20 }">Go to Section 1</a> |
        <a href="#section2" v-smooth-scroll="{ container: '#scrollContainer', duration: 1200 }">Go to Section 2 (in container)</a> |
        <button @click="scrollToMyEl" style="margin-left: 10px;">Scroll to My Element (Programmatic)</button>
      </nav>

      <div style="height: 500px; background: #f0f0f0; margin-top: 20px; padding: 20px;">
        <p>Content before sections to allow sufficient scrolling space.</p>
        <p>This area provides initial context before the scroll targets.</p>
      </div>

      <section id="section1" style="height: 400px; background: lightblue; padding: 20px; border-radius: 8px; margin-top: 40px;">
        <h2>Section 1</h2>
        <p>This is the first section. We will scroll here using a directive with custom options.</p>
      </section>

      <div id="scrollContainer" style="height: 300px; overflow-y: scroll; border: 1px solid #ccc; margin-top: 40px; border-radius: 8px;">
        <div style="height: 600px; padding: 20px;">
          <p>Content inside a custom scroll container.</p>
          <p>Scrolling within this container is independent of the main window scroll.</p>
          <div style="height: 200px; background: #e0f7fa; margin: 15px 0;">Placeholder</div>
          <section id="section2" ref="myContainerEl" style="height: 150px; background: lightcoral; padding: 10px; border-radius: 5px;">
            <h3>Section 2 (inside container)</h3>
            <p>This section is specifically located inside the custom scrollable div.</p>
          </section>
        </div>
      </div>

      <div style="height: 700px; background: #f0f0f0; margin-top: 40px; padding: 20px;">
        <p>More content after sections to ensure the ability to scroll back up and down.</p>
        <p>This helps in testing the scroll behavior effectively.</p>
      </div>

      <div ref="myEl" style="height: 100px; background: lightgreen; margin-top: 50px; padding: 20px; border-radius: 8px;">
        <h3>My Programmatic Target Element</h3>
        <p>This element is targeted programmatically from the button click.</p>
      </div>
    </div>
  `,
  setup() {
    const myEl = ref(null);
    const smoothScroll = inject('smoothScroll');

    const scrollToMyEl = () => {
      if (smoothScroll && myEl.value) {
        smoothScroll({
          scrollTo: myEl.value,
          duration: 700,
          offset: -100,
          hash: '#myProgrammaticTarget' // Optional hash update
        });
      }
    };

    return {
      myEl,
      scrollToMyEl
    };
  }
};

const app = createApp(App);
app.use(VueSmoothScroll, {
  duration: 500,
  updateHistory: true // Global default for history updates
});
app.mount('#app');

view raw JSON →