JAVASCRIPT

Programmatic Scroll Control and Scroll-to-Element Composable in Vue 3

Learn to create a Vue 3 composable for programmatically scrolling to specific elements or to the top/bottom of the page with smooth animations.

// composables/useScroll.js
import { ref, onMounted, onUnmounted } from 'vue';

export function useScroll() {
  const scrollTop = ref(0);
  const scrollLeft = ref(0);

  const updateScrollPosition = () => {
    scrollTop.value = window.scrollY;
    scrollLeft.value = window.scrollX;
  };

  /**
   * Scrolls the window to the top.
   * @param {'smooth' | 'auto'} behavior - Defines the animation behavior.
   */
  const scrollToTop = (behavior = 'smooth') => {
    window.scrollTo({ top: 0, behavior });
  };

  /**
   * Scrolls the window to the bottom.
   * @param {'smooth' | 'auto'} behavior - Defines the animation behavior.
   */
  const scrollToBottom = (behavior = 'smooth') => {
    window.scrollTo({ top: document.documentElement.scrollHeight, behavior });
  };

  /**
   * Scrolls the window to a specific element.
   * @param {Ref<HTMLElement>} elementRef - A ref to the target element.
   * @param {'smooth' | 'auto'} behavior - Defines the animation behavior.
   * @param {number} offset - An additional offset in pixels from the element's top position.
   */
  const scrollToElement = (elementRef, behavior = 'smooth', offset = 0) => {
    if (elementRef.value) {
      // Get the element's position relative to the viewport, then add current scrollY to get its absolute position
      const elementPosition = elementRef.value.getBoundingClientRect().top + window.scrollY;
      window.scrollTo({
        top: elementPosition + offset,
        behavior: behavior,
      });
    } else {
      console.warn('scrollToElement: elementRef is null or undefined. Cannot scroll.');
    }
  };

  onMounted(() => {
    window.addEventListener('scroll', updateScrollPosition);
    updateScrollPosition(); // Set initial position on mount
  });

  onUnmounted(() => {
    window.removeEventListener('scroll', updateScrollPosition);
  });

  return {
    scrollTop,
    scrollLeft,
    scrollToTop,
    scrollToBottom,
    scrollToElement,
  };
}

// Usage in a Vue component:
<template>
  <div style="height: 2000px; padding: 20px;">
    <p>Current Scroll Top: {{ scrollTop }}px</p>
    <button @click="scrollToTop()">Scroll to Top</button>
    <button @click="scrollToBottom('auto')" style="margin-left: 10px;">Scroll to Bottom (instant)</button>

    <div style="height: 800px; background-color: #f0f0f0; margin-top: 20px; padding: 15px; border-radius: 5px;">
      <p>This is a long content section to demonstrate scrolling capabilities.</p>
      <p>Scroll down further to see the target element button.</p>
    </div>

    <button @click="scrollToElement(targetElement, 'smooth', -70)" style="margin-top: 30px;">Scroll to Target Element</button>

    <div ref="targetElement" style="height: 300px; background-color: lightblue; margin-top: 150px; padding: 20px; border-radius: 5px;">
      <h2>I am the target element!</h2>
      <p>This is where the 'Scroll to Target Element' button will bring you, with an offset.</p>
    </div>

    <div style="height: 600px; background-color: #f0f0f0; margin-top: 50px; padding: 15px; border-radius: 5px;">
      <p>More content below the target element.</p>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { useScroll } from './composables/useScroll.js';

const { scrollTop, scrollToTop, scrollToBottom, scrollToElement } = useScroll();
const targetElement = ref(null); // Reference to the element to scroll to
</script>

<style scoped>
button {
  padding: 10px 15px;
  background-color: #28a745;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.3s ease;
}

button:hover {
  background-color: #218838;
}
</style>
How it works: This `useScroll` composable for Vue 3 provides a comprehensive solution for programmatic scroll control within your application. It exposes reactive `scrollTop` and `scrollLeft` values that update with the window's scroll position. Additionally, it offers utility functions like `scrollToTop` and `scrollToBottom` for basic navigation, and `scrollToElement` to smoothly scroll to any specified DOM element reference, complete with an optional pixel offset. This composable is ideal for creating interactive navigation, single-page application experiences, or any scenario requiring fine-grained control over scrolling.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs