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
Comprehensive configuration system for customizing OverlayScrollbars behavior, appearance, and functionality through nested options objects.
interface OverlayScrollbarsOptions {
className?: string | null;
}CSS class name applied to the host element for custom styling.
Type: String | null
Default: "os-theme-dark"
// Apply custom theme
OverlayScrollbars(element, {
className: "custom-scrollbar-theme"
});
// Remove default theme
OverlayScrollbars(element, {
className: null
});interface OverlayScrollbarsOptions {
resize?: "none" | "both" | "horizontal" | "vertical";
}Controls resize behavior for the scrollbars.
Type: String
Default: "none"
Values: "none", "both", "horizontal", "vertical"
OverlayScrollbars(element, {
resize: "both" // Allow resizing in both directions
});interface OverlayScrollbarsOptions {
sizeAutoCapable?: boolean;
}Whether the plugin can automatically detect size changes.
Type: Boolean
Default: true
interface OverlayScrollbarsOptions {
clipAlways?: boolean;
}Whether to always clip the content.
Type: Boolean
Default: true
interface OverlayScrollbarsOptions {
normalizeRTL?: boolean;
}Whether to normalize RTL (right-to-left) scrolling behavior.
Type: Boolean
Default: true
interface OverlayScrollbarsOptions {
paddingAbsolute?: boolean;
}Whether to use absolute positioning for padding.
Type: Boolean
Default: false
interface OverlayScrollbarsOptions {
autoUpdate?: boolean | null;
}Automatic update detection behavior.
Type: Boolean | null
Default: null
// Enable auto-update
OverlayScrollbars(element, {
autoUpdate: true
});
// Disable auto-update
OverlayScrollbars(element, {
autoUpdate: false
});
// Use recommended setting (null)
OverlayScrollbars(element, {
autoUpdate: null
});interface OverlayScrollbarsOptions {
autoUpdateInterval?: number;
}Interval in milliseconds for automatic updates.
Type: Number
Default: 33
interface OverlayScrollbarsOptions {
updateOnLoad?: string | string[] | null;
}Elements that trigger updates when loaded.
Type: String | Array | null
Default: ["img"]
// Update when images and videos load
OverlayScrollbars(element, {
updateOnLoad: ["img", "video"]
});
// Don't update on any element load
OverlayScrollbars(element, {
updateOnLoad: null
});interface OverlayScrollbarsOptions {
nativeScrollbarsOverlaid?: {
showNativeScrollbars?: boolean;
initialize?: boolean;
};
}Configuration for when native scrollbars are overlaid (like on macOS).
OverlayScrollbars(element, {
nativeScrollbarsOverlaid: {
showNativeScrollbars: false, // Hide native scrollbars
initialize: true // Initialize even when native are overlaid
}
});interface OverlayScrollbarsOptions {
overflowBehavior?: {
x?: "visible-hidden" | "visible-scroll" | "scroll" | "hidden";
y?: "visible-hidden" | "visible-scroll" | "scroll" | "hidden";
};
}Controls overflow behavior for horizontal and vertical axes.
Default: { x: "scroll", y: "scroll" }
OverlayScrollbars(element, {
overflowBehavior: {
x: "hidden", // Hide horizontal overflow
y: "scroll" // Allow vertical scrolling
}
});interface OverlayScrollbarsOptions {
scrollbars?: {
visibility?: "visible" | "hidden" | "auto";
autoHide?: "never" | "scroll" | "leave" | "move";
autoHideDelay?: number;
dragScrolling?: boolean;
clickScrolling?: boolean;
touchSupport?: boolean;
snapHandle?: boolean;
};
}Comprehensive scrollbar behavior configuration.
OverlayScrollbars(element, {
scrollbars: {
visibility: "auto", // Show scrollbars when needed
autoHide: "leave", // Hide when mouse leaves
autoHideDelay: 800, // Delay before hiding (ms)
dragScrolling: true, // Enable drag scrolling
clickScrolling: false, // Disable click scrolling on track
touchSupport: true, // Enable touch support
snapHandle: false // Don't snap handle to increments
}
});Controls when scrollbars are visible.
Values:
"visible" - Always visible"hidden" - Always hidden"auto" - Visible when content overflowsControls automatic hiding behavior.
Values:
"never" - Never auto-hide"scroll" - Hide after scrolling stops"leave" - Hide when mouse leaves scrollbar area"move" - Hide when mouse stops movingTime in milliseconds before auto-hiding scrollbars.
Type: Number
Default: 800
interface OverlayScrollbarsOptions {
textarea?: {
dynWidth?: boolean;
dynHeight?: boolean;
inheritedAttrs?: string | string[] | null;
};
}Special options for textarea elements.
OverlayScrollbars(textareaElement, {
textarea: {
dynWidth: false, // Don't adjust width dynamically
dynHeight: false, // Don't adjust height dynamically
inheritedAttrs: ["style", "class"] // Attributes to inherit
}
});interface OverlayScrollbarsOptions {
callbacks?: {
onInitialized?: (instance: OverlayScrollbarsInstance) => void;
onInitializationWithdrawn?: (instance: OverlayScrollbarsInstance) => void;
onDestroyed?: (instance: OverlayScrollbarsInstance) => void;
onScrollStart?: (instance: OverlayScrollbarsInstance) => void;
onScroll?: (instance: OverlayScrollbarsInstance) => void;
onScrollStop?: (instance: OverlayScrollbarsInstance) => void;
onOverflowChanged?: (instance: OverlayScrollbarsInstance) => void;
onOverflowAmountChanged?: (instance: OverlayScrollbarsInstance) => void;
onDirectionChanged?: (instance: OverlayScrollbarsInstance) => void;
onContentSizeChanged?: (instance: OverlayScrollbarsInstance) => void;
onHostSizeChanged?: (instance: OverlayScrollbarsInstance) => void;
onUpdated?: (instance: OverlayScrollbarsInstance) => void;
};
}Lifecycle and event callbacks.
OverlayScrollbars(element, {
callbacks: {
onInitialized: function(instance) {
console.log('OverlayScrollbars initialized');
},
onScrollStart: function(instance) {
console.log('Scrolling started');
},
onScroll: function(instance) {
const state = instance.getState();
console.log('Scroll position:', state.contentScrollSize);
},
onScrollStop: function(instance) {
console.log('Scrolling stopped');
},
onOverflowChanged: function(instance) {
const state = instance.getState();
console.log('Overflow changed:', state.hasOverflow);
},
onContentSizeChanged: function(instance) {
console.log('Content size changed');
// Useful for triggering other UI updates
},
onDestroyed: function(instance) {
console.log('Instance destroyed');
}
}
});const completeConfig = {
className: "custom-theme",
resize: "both",
sizeAutoCapable: true,
clipAlways: true,
normalizeRTL: true,
paddingAbsolute: false,
autoUpdate: null,
autoUpdateInterval: 33,
updateOnLoad: ["img", "video"],
nativeScrollbarsOverlaid: {
showNativeScrollbars: false,
initialize: true
},
overflowBehavior: {
x: "scroll",
y: "scroll"
},
scrollbars: {
visibility: "auto",
autoHide: "leave",
autoHideDelay: 1000,
dragScrolling: true,
clickScrolling: true,
touchSupport: true,
snapHandle: false
},
textarea: {
dynWidth: false,
dynHeight: false,
inheritedAttrs: ["style", "class"]
},
callbacks: {
onInitialized: function(instance) {
console.log('Initialized');
},
onScroll: function(instance) {
// Handle scroll events
},
onUpdated: function(instance) {
// Handle updates
}
}
};
const instance = OverlayScrollbars(element, completeConfig);interface OverlayScrollbarsOptions {
className?: string | null;
resize?: "none" | "both" | "horizontal" | "vertical";
sizeAutoCapable?: boolean;
clipAlways?: boolean;
normalizeRTL?: boolean;
paddingAbsolute?: boolean;
autoUpdate?: boolean | null;
autoUpdateInterval?: number;
updateOnLoad?: string | string[] | null;
nativeScrollbarsOverlaid?: NativeScrollbarsOverlaidOptions;
overflowBehavior?: OverflowBehaviorOptions;
scrollbars?: ScrollbarsOptions;
textarea?: TextareaOptions;
callbacks?: CallbackOptions;
}
interface NativeScrollbarsOverlaidOptions {
showNativeScrollbars?: boolean;
initialize?: boolean;
}
interface OverflowBehaviorOptions {
x?: "visible-hidden" | "visible-scroll" | "scroll" | "hidden";
y?: "visible-hidden" | "visible-scroll" | "scroll" | "hidden";
}
interface ScrollbarsOptions {
visibility?: "visible" | "hidden" | "auto";
autoHide?: "never" | "scroll" | "leave" | "move";
autoHideDelay?: number;
dragScrolling?: boolean;
clickScrolling?: boolean;
touchSupport?: boolean;
snapHandle?: boolean;
}
interface TextareaOptions {
dynWidth?: boolean;
dynHeight?: boolean;
inheritedAttrs?: string | string[] | null;
}
interface CallbackOptions {
onInitialized?: (instance: OverlayScrollbarsInstance) => void;
onInitializationWithdrawn?: (instance: OverlayScrollbarsInstance) => void;
onDestroyed?: (instance: OverlayScrollbarsInstance) => void;
onScrollStart?: (instance: OverlayScrollbarsInstance) => void;
onScroll?: (instance: OverlayScrollbarsInstance) => void;
onScrollStop?: (instance: OverlayScrollbarsInstance) => void;
onOverflowChanged?: (instance: OverlayScrollbarsInstance) => void;
onOverflowAmountChanged?: (instance: OverlayScrollbarsInstance) => void;
onDirectionChanged?: (instance: OverlayScrollbarsInstance) => void;
onContentSizeChanged?: (instance: OverlayScrollbarsInstance) => void;
onHostSizeChanged?: (instance: OverlayScrollbarsInstance) => void;
onUpdated?: (instance: OverlayScrollbarsInstance) => void;
}Install with Tessl CLI
npx tessl i tessl/npm-overlayscrollbars