Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Slick Scrollbar Laravel Package

muazzam/slick-scrollbar

muazzam/slick-scrollbar adds customizable, JavaScript-driven scrollbars to Laravel apps. Swap native browser scrollbars for slim, styled bars using a simple Blade directive or component, with configurable colors and sizes. Lightweight and easy to drop into any Blade view.

View on GitHub
Deep Wiki
Context7

Getting Started

muazzam/slick-scrollbar is a frontend asset package, not a backend feature package. It ships CSS/JS for replacing native browser scrollbars with a styled, custom-drawn scrollbar. Treat it the way you'd treat a UI library: install, publish assets, wire into your layout, then progressively apply it to containers that need it.

1. Install

composer require muazzam/slick-scrollbar

2. Publish whatever the provider exposes

Most asset-type Laravel packages register a publishable tag for the config and the CSS/JS files. Check with:

php artisan vendor:publish --provider="Muazzam\\SlickScrollbar\\SlickScrollbarServiceProvider"
# or, if tagged:
php artisan vendor:publish --tag=slick-scrollbar

Inspect vendor/muazzam/slick-scrollbar/ immediately after install — the README, config/, and resources/ (or dist/) folders tell you exactly what's publishable and whether a Blade directive or component is registered. This is the first place to look, because with 13 stars the README is the only reliable documentation you'll get.

3. Include assets in your layout

If the package ships plain assets, reference them from your main layout:

{{-- resources/views/layouts/app.blade.php --}}
@push('styles')
    <link rel="stylesheet" href="{{ asset('vendor/slick-scrollbar/slick-scrollbar.css') }}">
@endpush

@push('scripts')
    <script src="{{ asset('vendor/slick-scrollbar/slick-scrollbar.js') }}"></script>
@endpush

If you use Vite, prefer importing the published file from your resources/js/app.js / app.css instead, so it's bundled and cache-busted alongside everything else.

4. First use case

Don't apply it globally on day one. Pick a single scrollable region where the native scrollbar is visually wrong — a sidebar nav, a chat/message panel, or a horizontally scrolling data table wrapper. Add the package's required class or data attribute to that container, initialize it, and confirm behavior before rolling it out.

<div class="slick-scrollbar" style="max-height: 400px; overflow-y: auto;">
    @foreach ($notifications as $notification)
        @include('notifications.item', ['notification' => $notification])
    @endforeach
</div>

Implementation Patterns

Centralize initialization in one entrypoint. Rather than inlining init calls in every Blade file, put the bootstrap in resources/js/app.js and have it scan for a known selector or data- attribute:

import './bootstrap';
import SlickScrollbar from './vendor/slick-scrollbar'; // or window.SlickScrollbar

function initScrollbars(root = document) {
    root.querySelectorAll('[data-slick-scrollbar]').forEach((el) => {
        if (el.dataset.slickInitialized) return;   // idempotency guard
        new SlickScrollbar(el);
        el.dataset.slickInitialized = 'true';
    });
}

document.addEventListener('DOMContentLoaded', () => initScrollbars());
window.initScrollbars = initScrollbars; // expose for Livewire/Alpine

Opting in via data-slick-scrollbar on containers is far more maintainable than a global *::-webkit-scrollbar override, and it keeps the blast radius small when the package misbehaves.

Wrap it into a Blade component. Once you know the markup contract, wrap it so views stay declarative:

{{-- resources/views/components/scroll-panel.blade.php --}}
@props(['height' => '24rem'])

<div {{ $attributes->merge(['class' => 'relative overflow-y-auto', 'data-slick-scrollbar' => true]) }}
     style="max-height: {{ $height }};">
    {{ $slot }}
</div>

Usage: <x-scroll-panel height="32rem">...</x-scroll-panel>. This becomes the single seam for swapping or removing the package later.

Livewire / Turbo / Inertia. Any time the DOM is replaced outside a full page load, re-run initialization against the new subtree:

document.addEventListener('livewire:navigated', () => initScrollbars());
Livewire.hook('morph.updated', ({ el }) => initScrollbars(el));

For Inertia, hook router.on('finish', ...) or call initScrollbars() inside onMounted of the page component.

Alpine.js integration works well because Alpine already owns per-element lifecycle:

<div
    x-data
    x-init="window.initScrollbars($el.parentElement)"
    class="overflow-y-auto max-h-96">
    ...
</div>

Theming via CSS variables. Custom scrollbar libraries almost always expose colors/widths as CSS custom properties. Define them once in your Tailwind theme layer and switch them under .dark:

:root {
    --slick-scrollbar-thumb: theme('colors.slate.300');
    --slick-scrollbar-track: transparent;
    --slick-scrollbar-width: 8px;
}
.dark {
    --slick-scrollbar-thumb: theme('colors.slate.600');
}

This avoids forking the package just to change a color.

Progressive enhancement. Always keep the container scrollable without the package — i.e., real overflow-y: auto and a max-height. If the JS fails to load (ad blockers, CSP, old browser), users still get native scrolling. Never make visibility or truncation depend on the package running.


Gotchas and Tips

It's frontend-only — don't hunt for Eloquent or config magic. There's no model, no migration, no queue integration. The composer.json presence is just a delivery mechanism. If you were expecting server-side behavior, you're looking at the wrong package.

License is NOASSERTION. Composer reports no recognized SPDX license. Before shipping commercially, open the repo's LICENSE file directly and confirm the terms. If there isn't one, treat it as all-rights-reserved and consider whether you can legally vendor it — or reimplement the 200-line behavior yourself.

13 stars, 0 dependents, single maintainer. This is a bus-factor-of-one utility. Pin the exact version in composer.json ("muazzam/slick-scrollbar": "1.x.x" style) and, given how small the surface area is, consider copying the CSS/JS into resources/ rather than depending on Composer at all. You get the code, no supply-chain risk, and full control.

Re-initialization is the #1 bug source. Livewire morphs, Turbo frames, and v-if/x-show toggles will leave you with orphaned instances or duplicated scrollbars. Always guard with a data-* flag (as above) or call the library's destroy() if it exposes one, before re-init.

CSS specificity fights with Tailwind. Custom scrollbar libraries typically inject ::-webkit-scrollbar rules with element or class selectors. Tailwind's scrollbar-* utilities (if you add the plugin) or your own overrides may lose. Keep the package's selectors scoped under your data attribute and use @layer if you're on Tailwind v3+ to control ordering.

Bundle it through Vite, don't hand-publish twice. If you vendor:publish assets and import them through Vite, you'll load two copies and wonder why theming partially applies. Pick one pipeline. Vite is preferable for cache-busting and tree-shaking.

Watch for layout shift on hydration. If the JS measures container size on init, expect a flicker on first paint. Mitigate by setting explicit max-height/height on the container in CSS rather than letting the script infer it.

Performance in long lists. One instance per container is fine; hundreds (e.g., a card grid each with its own scroll area) will tank scroll performance. Use the package only on the handful of regions that actually need custom styling, and let native scrollbars handle the rest.

CSP and inline scripts. Some packages inject a <style> tag or use element.style writes. Strict Content-Security-Policy setups (style-src without 'unsafe-inline') may block the theming. Check the browser console the first time you load a page — that's your fastest diagnostic.

Debugging checklist when the scrollbar doesn't appear:

  1. Is the container actually scrollable? (scrollHeight > clientHeight — check in DevTools.)
  2. Did initScrollbars run after the element existed? (Add a console.log count.)
  3. Is another stylesheet overriding overflow?
  4. Does the element get re-rendered by Livewire/Alpine, wiping the instance?
  5. Are the assets 404ing under public/vendor/...?

Extension point to plan for. Because the package is tiny and lightly maintained, wrap access behind your own x-scroll-panel component and one initScrollbars() function. When you inevitably swap it out — for OverlayScrollbars, simplebar, or pure CSS scrollbar-color — you change two files, not every view.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings