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.