vue2-horizontal-scrollbar
v0.0.2
Published
A customizable horizontal scrollbar component for Vue 2
Maintainers
Readme
Vue2 Horizontal Scrollbar
A customizable horizontal scrollbar component for Vue 2 that provides smooth scrolling experience with keyboard support and touch gestures.
✨ Features
- 🎯 Vue 2 & TypeScript - Full TypeScript support with Vue 2 Options API
- 🎨 Customizable - Flexible styling and configuration options
- ♿ Accessible - ARIA labels and keyboard navigation support
- 📱 Touch Friendly - Mobile-friendly touch gestures
- 🚀 Performance - Optimized with throttling and efficient updates
- 🎪 Flexible - Works with any scrollable content
- 🎛️ Event Rich - Comprehensive event system for interactions
- 📦 Lightweight - Minimal dependencies
📦 Installation
# npm
npm install vue2-horizontal-scrollbar
# yarn
yarn add vue2-horizontal-scrollbar
# pnpm
pnpm add vue2-horizontal-scrollbar📺 Demo
Vue2 Horizontal Scrollbar Demo
🚀 Quick Start
Basic Usage
<template>
<div>
<!-- Your scrollable content -->
<div id="scroll-container" style="overflow-x: auto; width: 100%;">
<div id="scroll-content" style="width: 2000px; height: 200px;">
<!-- Wide content here -->
<p>This content is wider than the container...</p>
</div>
</div>
<!-- Horizontal Scrollbar -->
<VueHorizontalScrollbar
target-selector="#scroll-container"
content-selector="#scroll-content"
:auto-show="true"
@scroll="onScroll"
/>
</div>
</template>
<script>
import { VueHorizontalScrollbar } from 'vue2-horizontal-scrollbar'
import "vue2-horizontal-scrollbar/dist/style.css"
export default {
components: {
VueHorizontalScrollbar
},
methods: {
onScroll(info) {
console.log('Scroll info:', info)
// { scrollLeft: 100, maxScroll: 1000, scrollPercent: 10 }
}
}
}
</script>Global Registration
// main.ts
import Vue from 'vue'
import VueHorizontalScrollbar from 'vue2-horizontal-scrollbar'
import "vue2-horizontal-scrollbar/dist/style.css"
import App from './App.vue'
Vue.use(VueHorizontalScrollbar)
new Vue({
render: h => h(App)
}).$mount('#app')
<!-- Now you can use it globally -->
<template>
<VueHorizontalScrollbar
target-selector="#my-container"
content-selector="#my-content"
/>
</template>
📖 API Reference
Props
| Prop | Type | Default | Description |
|-------------------|--------------------|--------------------------|-----------------------------------------------------------------------------|
| targetSelector | string \| Function | — | Required. CSS selector or function returning the scroll container element |
| contentSelector | string \| Function | — | Required. CSS selector or function returning the content element |
| autoShow | boolean | true | Auto show/hide scrollbar based on content width |
| minScrollDistance | number | 50 | Minimum scroll distance to show scrollbar (when autoShow is true) |
| height | number | 16 | Scrollbar height in pixels |
| enableKeyboard | boolean | true | Enable keyboard navigation (Arrow keys, Home, End) |
| scrollStep | number | 50 | Scroll step for keyboard navigation |
| minThumbWidth | number | 30 | Minimum thumb width in pixels |
| throttleDelay | number | 16 | Throttle delay for scroll events in milliseconds |
| zIndex | number | 9999 | Z-index for the scrollbar |
| disabled | boolean | false | Disable the scrollbar |
| ariaLabel | string | 'Horizontal scrollbar' | ARIA label for accessibility |
| teleportTo | string | 'body' | Target element for scrollbar positioning (Vue 2 compatibility) |
Events
| Event | Payload | Description |
|-------------|-------------------------|----------------------------------------|
| scroll | ScrollInfo | Emitted when scrolling occurs |
| click | MouseEvent | Emitted when scrollbar track is clicked|
| dragStart | MouseEvent \| TouchEvent | Emitted when dragging starts |
| dragEnd | MouseEvent \| TouchEvent | Emitted when dragging ends |
| keydown | KeyboardEvent | Emitted on keyboard interaction |
| ready | - | Emitted when component is initialized |
| error | Error | Emitted when an error occurs |
🔧 Usage Example
<HorizontalScrollbar
:target-selector="'.scroll-container'"
:content-selector="'.scroll-content'"
:auto-show="true"
:scroll-step="60"
:height="20"
@scroll="onScroll"
@dragStart="onDragStart"
@dragEnd="onDragEnd"
/>
### ScrollInfo Type
```ts
interface ScrollInfo {
scrollLeft: number // Current scroll position
maxScroll: number // Maximum scroll position
scrollPercent: number // Scroll percentage (0-100)
}Exposed Methods
interface ExposedAPI {
scrollToPosition: (position: number) => void
scrollToEnd: () => void
updateScrollInfo: () => void
scrollLeft: number
maxScroll: number
scrollPercent: number
}🎨 Advanced Usage
Using Function Selectors
<template>
<div ref="containerRef">
<div ref="contentRef">
<!-- content -->
</div>
</div>
<VueHorizontalScrollbar
:target-selector="getContainer"
:content-selector="getContent"
/>
</template>
<script>
import { VueHorizontalScrollbar } from 'vue2-horizontal-scrollbar'
import "vue2-horizontal-scrollbar/dist/style.css"
export default {
components: {
VueHorizontalScrollbar
},
data() {
return {
containerRef: null,
contentRef: null
}
},
methods: {
getContainer() {
return this.$refs.containerRef
},
getContent() {
return this.$refs.contentRef
}
}
}const getContent = () => contentRef.value
### Element Plus Table Use
```vue
<template>
<el-table style="width: 100%">
</el-table>
<HorizontalScrollbar
:target-selector="getSelector('.el-table__body-wrapper .el-scrollbar .el-scrollbar__wrap')"
:content-selector="getSelector('.el-table__body-wrapper .el-scrollbar .el-scrollbar__view')"
/>
</template>
<script setup>
import { ref } from 'vue'
import { VueHorizontalScrollbar } from 'vue2-horizontal-scrollbar'
import "vue2-horizontal-scrollbar/dist/style.css"
function getSelector(selector: string) {
const elements = document.querySelectorAll<HTMLElement>(selector)
if (elements.length) {
return elements[elements.length - 1]
}
else {
console.warn(`Selector "${selector}" did not match any elements.`)
return null
}
}
</script>Programmatic Control
<template>
<VueHorizontalScrollbar
ref="scrollbarRef"
target-selector="#container"
content-selector="#content"
/>
<div class="controls">
<button @click="scrollToStart">Start</button>
<button @click="scrollToMiddle">Middle</button>
<button @click="scrollToEnd">End</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { VueHorizontalScrollbar } from 'vue2-horizontal-scrollbar'
import "vue2-horizontal-scrollbar/dist/style.css"
const scrollbarRef = ref()
function scrollToStart() {
scrollbarRef.value?.scrollToPosition(0)
}
function scrollToMiddle() {
const maxScroll = scrollbarRef.value?.maxScroll || 0
scrollbarRef.value?.scrollToPosition(maxScroll / 2)
}
function scrollToEnd() {
scrollbarRef.value?.scrollToEnd()
}
</script>Event Handling
<template>
<VueHorizontalScrollbar
target-selector="#container"
content-selector="#content"
@scroll="handleScroll"
@dragStart="handleDragStart"
@dragEnd="handleDragEnd"
@ready="handleReady"
@error="handleError"
/>
</template>
<script setup>
import { VueHorizontalScrollbar } from 'vue2-horizontal-scrollbar'
function handleScroll(info) {
console.log(`Scrolled to ${info.scrollPercent.toFixed(1)}%`)
}
function handleDragStart(event) {
console.log('Drag started')
}
function handleDragEnd(event) {
console.log('Drag ended')
}
function handleReady() {
console.log('Scrollbar is ready')
}
function handleError(error) {
console.error('Scrollbar error:', error)
}
</script>🎨 Styling
CSS Custom Properties
The component uses CSS custom properties for easy theming:
.vue-horizontal-scrollbar {
--scrollbar-bg: #f5f5f5;
--scrollbar-track: #e8e8e8;
--scrollbar-thumb: #c0c0c0;
--scrollbar-thumb-hover: #a0a0a0;
--scrollbar-thumb-active: #909090;
}Custom Styling
<template>
<VueHorizontalScrollbar
target-selector="#container"
content-selector="#content"
class="custom-scrollbar"
/>
</template>
<style>
.custom-scrollbar {
--scrollbar-bg: rgba(0, 0, 0, 0.1);
--scrollbar-track: rgba(0, 0, 0, 0.2);
--scrollbar-thumb: #007acc;
--scrollbar-thumb-hover: #005a9e;
--scrollbar-thumb-active: #004578;
}
.custom-scrollbar .custom-scrollbar-thumb {
border-radius: 2px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
</style>📱 Responsive Design
The component includes responsive breakpoints:
/* Mobile devices */
@media (max-width: 768px) {
.bottom-scrollbar-container {
padding: 2px 4px;
}
}♿ Accessibility
ARIA Labels
Uses appropriaterole,aria-valuenow,aria-valuemin, andaria-valuemaxattributes to describe the scrollbar’s state.Keyboard Navigation
Fully supports keyboard interactions for navigating content:- Arrow keys (
←,→) HomeandEndkeys
- Arrow keys (
Focus Management
Includes visible focus indicators to help keyboard users navigate the interface.Screen Reader Support
Designed with semantic HTML and proper ARIA attributes to ensure compatibility with screen readers.
⌨️ Keyboard Shortcuts
| Key | Action |
|-------|------------------|
| ← | Scroll left |
| → | Scroll right |
| Home| Scroll to start |
| End | Scroll to end |
🔧 TypeScript Support
Full TypeScript support with comprehensive type definitions:
import type {
HorizontalScrollbarProps,
HorizontalScrollbarEmits,
ScrollInfo,
ElementSelector
} from 'vue2-horizontal-scrollbar'🌟 Examples
Table Horizontal Scroll
<template>
<div class="table-container">
<div id="table-wrapper" class="table-wrapper">
<table id="wide-table" class="wide-table">
<thead>
<tr>
<th v-for="i in 20" :key="i">Column {{ i }}</th>
</tr>
</thead>
<tbody>
<tr v-for="row in 10" :key="row">
<td v-for="col in 20" :key="col">
Data {{ row }}-{{ col }}
</td>
</tr>
</tbody>
</table>
</div>
<VueHorizontalScrollbar
target-selector="#table-wrapper"
content-selector="#wide-table"
:height="20"
/>
</div>
</template>
<style>
.table-wrapper {
overflow-x: auto;
overflow-y: hidden;
width: 100%;
}
.wide-table {
min-width: 1200px;
border-collapse: collapse;
}
.wide-table th,
.wide-table td {
padding: 8px 12px;
border: 1px solid #ddd;
white-space: nowrap;
}
</style>Image Gallery
<template>
<div class="gallery-container">
<div id="gallery-scroll" class="gallery-scroll">
<div id="gallery-content" class="gallery-content">
<img
v-for="i in 10"
:key="i"
:src="`https://picsum.photos/300/200?random=${i}`"
:alt="`Image ${i}`"
class="gallery-image"
/>
</div>
</div>
<VueHorizontalScrollbar
target-selector="#gallery-scroll"
content-selector="#gallery-content"
:scroll-step="300"
/>
</div>
</template>
<style>
.gallery-scroll {
overflow-x: auto;
overflow-y: hidden;
width: 100%;
}
.gallery-content {
display: flex;
gap: 16px;
padding: 16px 0;
}
.gallery-image {
flex-shrink: 0;
width: 300px;
height: 200px;
object-fit: cover;
border-radius: 8px;
}
</style>