mrshanebarron/carousel
mrshanebarron/carousel is a Laravel/PHP carousel package for adding configurable, responsive sliders to Blade views. It offers simple setup, customizable slides, and lightweight integration for image or content carousels.
Install and confirm discovery. composer require mrshanebarron/carousel. It's a Laravel UI component package, so it should ride package discovery — verify with php artisan about (providers/Blade section) or, on a non-discovered setup, add the provider to bootstrap/providers.php (Laravel 11+) / config/app.php. If the <x-...> tag is "not found" later, this is the first thing to check.
Publish config and views. List the tags the package actually offers before publishing anything:
php artisan vendor:publish --provider="MrShanebarron\Carousel\CarouselServiceProvider"
Then publish only what you need by tag (typically something like --tag=sb-config and --tag=sb-views). Do not run vendor:publish without a tag — it dumps every publishable asset the package owns, which you then tacitly own forever.
Confirm the config filename. This is the entire substance of v1.0.1 ("Fix config file naming (sb- prefix)"). On a fresh install the published file should be config/sb-carousel.php. If you see config/carousel.php, you are either on 1.0.0 or reading docs written against it — treat the file on disk as truth and rename/republish.
Where to look first, in order:
config/sb-carousel.php — autoplay, loop, speed, transition, and nav defaults. This is the package's real API.resources/views/components/ — the exact component tag name and the props/slots it accepts. The docs are thin (see Gotchas), so the Blade source is the contract.@push/@once.First use case: one hero carousel on one page. Three slides, autoplay off, arrows + dots, real <img> with alt text. Validate keyboard (Tab to controls, arrow keys if supported), swipe on a real phone, and that it doesn't break layout before you introduce this into a shared layout or a second page.
If the README still shows the un-prefixed filename, assume docs lag the release and go by what's on disk.
Per-instance props for what varies, config for global defaults. Autoplay belongs on a marketing hero and never on a product gallery or an announcement bar. Keep the config file for house defaults (speed, transition, loop) and pass per-usage values at the call site — e.g. <x-carousel :autoplay="false" :loop="true">. Anything that differs between two carousels on the same site should not live in config.
Wrap the component once, use it everywhere. Create resources/views/components/site/carousel.blade.php that renders the package component and normalises your props/slide shape. This gives you one place to fix issues (the tag name, the slide markup, the wrapper classes) and insulates the rest of the app from package churn — which matters more than usual for a 0-star, single-maintainer package.
Slot-based for editorial, data-driven for collections. Hand-authored slides (hero, promo) fit a slot: <x-slot:slides> or default slot with your own slide markup. For a "featured products" rail, loop a collection and render slides from it — don't hand-write five nearly-identical blocks.
Images are the real work. The component controls the carousel, not your media strategy:
fetchpriority="high", no loading="lazy". Subsequent slides: loading="lazy" + decoding="async".srcset/sizes, and a fixed aspect-ratio on the slide container to avoid layout shift as slides load.alt. Decorative slides get alt="" and role="presentation"; meaningful ones get real alt text. This is the accessibility claim in the description, and it's on you, not the package.Respect the accessibility contract you're paying for. The package advertises keyboard and touch/swipe navigation, but that only holds if you don't break it: controls must be real <button>/<a> elements, focus must be visible, and autoplay should be off by default in your wrapper. WCAG 2.2.2 requires a pause/stop mechanism for anything that auto-advances — gate autoplay behind a config flag and honour prefers-reduced-motion in your CSS with @media (prefers-reduced-motion: reduce) { … transition: none }.
Stay style-agnostic on purpose. The package ships no framework dependency, which means it ships (at best) minimal or no styling. Do all visual work in your Tailwind/CSS layer against the classes the component emits. Before writing CSS, dump the rendered HTML (php artisan tinker + Blade::render, or just view-source) and target the actual class names rather than guessing.
Integration with Livewire / Turbo / Inertia. This is server-rendered Blade with JS behaviour attached on load. In Livewire, wrap the carousel in wire:ignore and re-mount on data change, or the DOM swap will silently strip the JS handlers. With Turbo Drive or Inertia, the carousel will work on first visit and die on client-side navigation — you need to re-init on turbo:load / router.on('navigate') unless the package handles it.
Testing. The cheap and high-value test is a render assertion: a feature test that GETs the page and asserts the slide text and image URLs appear, and that a non-published-content slide does not. Also snapshot-test the first slide's markup — that's where CLS and alt-text regressions show up.
Content workflow. Drive slide content from whatever already owns it (a Page/Banner model, a settings table) rather than hardcoding in Blade. A carousel is the most-edited thing on a marketing page; if editing it requires a deploy, you'll be doing deploys.
1.0.0, the old filename stays on disk while the provider reads/merges sb-carousel.php. mergeConfigFrom() finds nothing, your overrides are ignored, and defaults apply with no error. Fix: diff your existing file against the new stub, port values across, then php artisan config:clear. Prefer that to --force, which clobbers your customisations.config:cache masks every config change. Nothing you do to config/sb-carousel.php or .env takes effect in a cached environment until you re-cache. "My autoplay setting isn't applying" is this nine times out of ten. Locally: php artisan config:clear; in deploy: php artisan config:cache as a deploy step.mergeConfigFrom() replaces top-level keys. If you customise one value inside a nested block (e.g. navigation sub-keys), restate the whole block or you lose its siblings.vendor/. Publish the views and own them. For a small component this is genuinely the right call: vendoring the Blade file into resources/views/vendor/... (or your own component) means a future package release can't break your markup, and the package has few enough moving parts that you can maintain it.<x-carousel>, Blade resolves to yours and the package appears inert. Check the tag name from the package's view directory rather than assuming.touch-action: pan-y on the track, not more JS.php artisan config:show sb-carousel (Laravel 11) — is your value actually loaded? (3) is config cached? (4) is the published filename sb--prefixed? (5) does the rendered HTML contain the classes/JS hooks your JS expects? (6) with a JS-bundled asset, is it in the Vite entry and did you rebuild?1.0.1 whose headline fix is a filename — that combination says the 1.0.0 surface was lightly tested. Pin ~1.0.1 in composer.json, read the diff before any minor bump, and keep the wrapper component from Implementation Patterns so an upstream change costs you one file. If the package is only a few hundred lines, the honest long-term option is to fork or inline it.1.x package and the least likely to be covered by tests.How can I help you explore Laravel packages today?