A javascript scrollbar plugin which hides native scrollbars, provides custom styleable overlay scrollbars and keeps the native functionality and feeling.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
OverlayScrollbars provides seamless jQuery integration through a dedicated plugin file that extends jQuery's prototype with the overlayScrollbars() method, enabling natural jQuery chaining and selector usage.
<!-- Include jQuery first -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- Include OverlayScrollbars CSS -->
<link rel="stylesheet" href="overlayscrollbars/css/OverlayScrollbars.min.css">
<!-- Include jQuery plugin version -->
<script src="overlayscrollbars/js/jquery.overlayScrollbars.min.js"></script>// ES modules
import $ from "jquery";
import "overlayscrollbars/js/jquery.overlayScrollbars.min.js";
// CommonJS
const $ = require("jquery");
require("overlayscrollbars/js/jquery.overlayScrollbars.min.js");interface JQuery {
overlayScrollbars(
options: OverlayScrollbarsOptions,
extensions?: OverlayScrollbarsExtensions
): JQuery;
overlayScrollbars(): OverlayScrollbarsInstance | OverlayScrollbarsInstance[];
}The jQuery plugin method behaves differently based on the arguments provided:
// Initialize with default options
$('.content').overlayScrollbars({});
// Initialize with custom options
$('.scrollable').overlayScrollbars({
className: "os-theme-dark",
scrollbars: {
autoHide: "leave",
autoHideDelay: 1000
},
callbacks: {
onScroll: function() {
console.log('jQuery: Scrolling...');
}
}
});
// jQuery chaining
$('.content')
.overlayScrollbars({
resize: "both",
scrollbars: { visibility: "auto" }
})
.addClass('initialized')
.fadeIn();// Get OverlayScrollbars instances (not jQuery objects)
const instances = $('.content').overlayScrollbars();
// Single element - returns single instance
const instance = $('#main-content').overlayScrollbars();
// Multiple elements - returns array of instances
const instanceArray = $('.multiple-content').overlayScrollbars();$('.content').overlayScrollbars({
callbacks: {
onInitialized: function(instance) {
// jQuery event trigger
$(instance.getElements('target')).trigger('os:initialized');
},
onScroll: function(instance) {
const $target = $(instance.getElements('target'));
$target.trigger('os:scroll', [instance]);
},
onDestroyed: function(instance) {
$(instance.getElements('target')).trigger('os:destroyed');
}
}
});
// Listen for custom events
$('.content').on('os:scroll', function(event, instance) {
console.log('OverlayScrollbars scroll event triggered');
});// Use with jQuery UI widgets
$('.content')
.overlayScrollbars({
scrollbars: { autoHide: "leave" }
})
.resizable({
resize: function() {
// Update OverlayScrollbars when resized
$(this).overlayScrollbars().update(true);
}
});
// Tab integration
$('#tabs').tabs({
activate: function(event, ui) {
// Update scrollbars in newly activated tab
ui.newPanel.find('.scrollable').each(function() {
const instance = $(this).overlayScrollbars();
if (instance) {
instance.update();
}
});
}
});// Initialize scrollbars
$('.dynamic-content').overlayScrollbars({
callbacks: {
onContentSizeChanged: function(instance) {
console.log('Content size changed via jQuery');
}
}
});
// Add content dynamically
$('.add-content-btn').click(function() {
const $content = $('.dynamic-content');
// Add new content
$content.append('<div class="new-item">New content item</div>');
// Update OverlayScrollbars
$content.overlayScrollbars().update();
});
// AJAX content loading
$.get('/api/content', function(data) {
$('.ajax-content')
.html(data)
.overlayScrollbars() // Get instance
.update(true); // Force update
});// Animate and scroll
$('.content').overlayScrollbars({
scrollbars: { autoHide: "scroll" }
});
$('.scroll-to-bottom').click(function() {
const instance = $('.content').overlayScrollbars();
// Scroll with OverlayScrollbars animation
instance.scroll({ y: '100%' }, 1000, 'swing', function() {
// Animation complete - trigger jQuery animation
$('.content').effect('highlight', { color: '#ff0' }, 500);
});
});$(window).resize(function() {
// Update all OverlayScrollbars instances on window resize
$('.scrollable').each(function() {
const instance = $(this).overlayScrollbars();
if (instance && !instance.getState().destroyed) {
instance.update(true);
}
});
});
// Media query handling
function handleMediaChange(mq) {
if (mq.matches) {
// Mobile view - different scrollbar settings
$('.content').overlayScrollbars().options({
scrollbars: {
touchSupport: true,
autoHide: "leave"
}
});
} else {
// Desktop view
$('.content').overlayScrollbars().options({
scrollbars: {
touchSupport: false,
autoHide: "scroll"
}
});
}
}
const mediaQuery = window.matchMedia('(max-width: 768px)');
mediaQuery.addListener(handleMediaChange);
handleMediaChange(mediaQuery);$(document).ready(function() {
// Initialize OverlayScrollbars on all scrollable elements
$('.scrollable').overlayScrollbars({
className: "os-theme-thin-dark",
resize: "none",
scrollbars: {
visibility: "auto",
autoHide: "leave",
autoHideDelay: 800,
dragScrolling: true,
clickScrolling: false,
touchSupport: true
},
callbacks: {
onInitialized: function() {
console.log('OverlayScrollbars initialized via jQuery');
},
onScroll: function(instance) {
// Update scroll indicator
const state = instance.getState();
const scrollPercent = (state.viewportSize.height / state.contentScrollSize.height) * 100;
$('.scroll-indicator').width(scrollPercent + '%');
}
}
});
// Navigation scroll links
$('.nav-link').click(function(e) {
e.preventDefault();
const target = $(this).attr('href');
const instance = $('.main-content').overlayScrollbars();
instance.scroll(target, 800, 'easeInOutQuad');
});
// Destroy on modal close
$('.modal').on('hidden.bs.modal', function() {
$(this).find('.scrollable').overlayScrollbars().destroy();
});
});// Textarea with OverlayScrollbars
$('textarea.enhanced').overlayScrollbars({
className: "os-theme-minimal",
textarea: {
dynHeight: false,
dynWidth: false
},
scrollbars: {
visibility: "auto",
autoHide: "never"
}
});
// Form validation with scroll to error
$('#myForm').on('submit', function() {
const $firstError = $(this).find('.error').first();
if ($firstError.length) {
const instance = $('.form-container').overlayScrollbars();
instance.scroll($firstError[0], 500);
return false;
}
});// Replace other jQuery scrollbar plugins
$('.content')
// .customScrollbar('destroy') // Remove old plugin
.overlayScrollbars({
scrollbars: {
visibility: "auto",
autoHide: "scroll"
}
});interface JQuery {
overlayScrollbars(
options: OverlayScrollbarsOptions,
extensions?: OverlayScrollbarsExtensions
): JQuery;
overlayScrollbars(
action?: string | function
): OverlayScrollbarsInstance | OverlayScrollbarsInstance[];
}
// jQuery-specific event data
interface JQueryOverlayScrollbarsEventData {
instance: OverlayScrollbarsInstance;
state: OverlayScrollbarsState;
elements: OverlayScrollbarsElements;
}Install with Tessl CLI
npx tessl i tessl/npm-overlayscrollbars