TypeScript First ย โขย Plugin Driven ย โขย WAAPI Powered ย โขย Framework Agnostic
BrickSlider is a TypeScript-first, Tailwind-first carousel engine focused on modern motion, clean markup, and plugin-driven features for production-ready sliders and story-style experiences.
The core is framework-agnostic, while the default authoring experience is built around clear markup, Tailwind-friendly styling, and plugins for accessibility helpers and story-style flows.
Website ย โขย Docs ย โขย Demo
- ๐ Support
- โ Why BrickSlider?
- ๐ฆ Packages
- ๐ฅ Installation
- ๐ CDN
- ๐ Quick Start
- ๐๏ธ Basic Configuration
- ๐ง TypeScript
- โ๏ธ Options
- ๐งฉ Methods
- ๐ก Events
- ๐ Plugins
- ๐งฑ Framework Guides
- ๐ค Project Links
If this project helps you, please consider supporting its development.
- ๐ GitHub Sponsors
- โจ Additional support link coming soon.
| Area | BrickSlider |
|---|---|
| Core architecture | TypeScript-first, framework-agnostic |
| Motion model | Web Animations API |
| Dependencies | No runtime dependencies in core |
| Stories experience | Dedicated plugin |
| Accessibility | Dedicated plugin |
| Styling approach | Tailwind-friendly markup with user-controlled classes |
| Extensibility | slider.use(plugin) |
- โ Written in TypeScript with no runtime dependencies
- โ Native Tailwind integration, no freakish inline CSS layout hacks
- โ Smooth, modern motion powered by the Web Animations API
- โ Supports variable slide sizes and custom breakpoints
- โ Includes a story-style carousel inspired by Instagram Stories
- โ Accessibility-friendly foundation with a dedicated plugin
BrickSlider is organized as a small monorepo with focused packages:
- ๐ฆ
@sixsrc/brick-sliderโ the core slider library - โฟ
@sixsrc/brick-slider-accessibilityโ accessibility helpers and announcements - ๐ฑ
@sixsrc/brick-slider-storiesโ story-style modal carousel behavior - ๐จ
@sixsrc/brick-slider-tailwindโ structural Tailwind utilities for BrickSlider markup
Install only the packages you need.
pnpm add @sixsrc/brick-slider
# or
npm install @sixsrc/brick-sliderpnpm add @sixsrc/brick-slider @sixsrc/brick-slider-accessibility
# or
npm install @sixsrc/brick-slider @sixsrc/brick-slider-accessibilitypnpm add @sixsrc/brick-slider @sixsrc/brick-slider-stories
# or
npm install @sixsrc/brick-slider @sixsrc/brick-slider-storiespnpm add @sixsrc/brick-slider @sixsrc/brick-slider-tailwind tailwindcss
# or
npm install @sixsrc/brick-slider @sixsrc/brick-slider-tailwind tailwindcssUse the official browser bundles in plain HTML:
<script src="https://cdn.jsdelivr.net/npm/@sixsrc/brick-slider@1.0.17/lib/brick-slider.browser.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@sixsrc/brick-slider-accessibility@1.0.10/lib/brick-slider-accessibility.browser.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@sixsrc/brick-slider-stories@1.0.13/lib/brick-slider-stories.browser.js"></script>
<script>
const { BrickSlider, AccessibilityPlugin, StoriesPlugin } = window
const slider = new BrickSlider("#slider", {
slidesPerView: 1,
slidesPerPage: 1
})
slider.use(new AccessibilityPlugin({ useKeyboardNavigation: true }))
slider.use(
new StoriesPlugin({ trigger: "#open-stories", duration: 5000 })
)
slider.init()
</script>ESMis the official runtime format for BrickSlider.- Browser CDN usage should use the official
.browser.jsbundles. - npm usage works with modern bundlers through the ESM entry.
UMDandCommonJSbuilds are no longer maintained.
import { BrickSlider } from "@sixsrc/brick-slider"
const slider = new BrickSlider("#slider", {
slidesPerView: 1,
slidesPerPage: 1,
gap: 16,
useLoop: false
})
slider.init()<div id="slider">
<button class="bs-arrow bs-prev" type="button">Prev</button>
<button class="bs-arrow bs-next" type="button">Next</button>
<div class="bs-pages"></div>
<div class="bs-track">
<div class="bs-container">
<div class="bs-slide">Slide 01</div>
<div class="bs-slide">Slide 02</div>
<div class="bs-slide">Slide 03</div>
</div>
</div>
<ul class="bs-dots">
<li class="bs-dot"></li>
</ul>
<div class="bs-progress">
<div class="bs-progress-bar"></div>
</div>
</div>Use the gap option for spacing between slides. Keep visual card spacing inside your slide content when you need custom design details.
Public types are exported from the package entries, so IntelliSense works out of the box.
import { BrickSlider } from "@sixsrc/brick-slider"
import type {
BrickSliderOptions,
BrickSliderSlideChangePayload,
ResponsiveBreakpoint,
ResponsiveInput
} from "@sixsrc/brick-slider"
const slider = new BrickSlider("#slider", {
slidesPerView: 1,
slidesPerPage: 1
})
slider.on("slideChange", (payload: BrickSliderSlideChangePayload) => {
console.log(payload.slideIndex, payload.activePage)
})import AccessibilityPlugin from "@sixsrc/brick-slider-accessibility"
import type { BrickSliderAccessibilityOptions } from "@sixsrc/brick-slider-accessibility"
slider.use(
new AccessibilityPlugin({
useKeyboardNavigation: true,
useFocusManagement: true
})
)import StoriesPlugin from "@sixsrc/brick-slider-stories"
import type { BrickSliderStoriesOptions } from "@sixsrc/brick-slider-stories"
slider.use(
new StoriesPlugin({ duration: 5000, maxStories: 10, closeOnEnd: true })
)const slider = new BrickSlider("#slider", {
gap: 20,
initialSlide: 2,
slidesPerPage: 1,
slidesPerView: 1,
slideSizes: {
0: 60,
1: 40
},
screens: {
xs: 320,
md: 768,
lg: 1024
},
responsive: {
xs: {
slidesPerView: 1,
slidesPerPage: 1,
slideSizes: { 0: 100 }
},
md: {
slidesPerView: 2,
slidesPerPage: 2,
slideSizes: { 0: 60, 1: 40 },
useSlidesPerView: false
},
lg: {
slidesPerView: 3,
slidesPerPage: 3,
useSlidesPerPage: false,
useSlideSizes: false
}
},
useTouch: true,
useLoop: true,
useDragFree: false,
useAutoHeight: false
})Spacing between slides in pixels.
Sets which slide should be active on mount.
initialSlide: 2Behavior:
0starts from the first slide- negative values are clamped to
0 - values greater than the last slide are clamped to the last valid slide
- decimal values are normalized to an integer
How many slides are advanced per paginated navigation step.
How many slides are visible at once.
A map of custom width percentages per slide index.
slideSizes: { 0: 65, 1: 35, 2: 25, 3: 75 }Breakpoint values used by the responsive config. Supported keys: xs, sm, md, lg, xl, 2xl.
Responsive overrides per breakpoint. Available keys: slidesPerView, slidesPerPage, slideSizes, useSlidesPerView, useSlidesPerPage, useSlideSizes.
Use the use* flags when you want to keep the breakpoint active but selectively ignore part of its config.
useSlidesPerView: falseignores the breakpointslidesPerViewvalue and keeps the base valueuseSlidesPerPage: falseignores the breakpointslidesPerPagevalue and keeps the base valueuseSlideSizes: falseignores both local and globalslideSizesat that breakpoint
Enables touch and drag interactions.
Creates an infinite carousel by cloning slides.
Disables paged snapping and allows free dragging.
Adjusts the slider height to the current visible content.
Mounts the slider.
Moves to the next or previous page.
Moves to a specific page index.
Restores the original markup snapshot.
Attaches a plugin instance to the slider.
Fired when the slider DOM and layout are ready. Payload: rootSelector.
slider.on("mounted", rootSelector => {
console.log(rootSelector)
})Fired whenever the active page changes. Payload: rootSelector, slideIndex, activePage.
slider.on("slideChange", payload => {
console.log(payload.slideIndex, payload.activePage)
})Fired after the slider is torn down. Payload: rootSelector.
slider.on("destroyed", rootSelector => {
console.log(rootSelector)
})- โฟ Accessibility Plugin
- ๐ฑ Stories Plugin
- ๐จ Tailwind Package
npm install @sixsrc/brick-slider @sixsrc/brick-slider-accessibilityimport { BrickSlider } from "@sixsrc/brick-slider"
import AccessibilityPlugin from "@sixsrc/brick-slider-accessibility"
const slider = new BrickSlider("#slider", {
slidesPerView: 1,
slidesPerPage: 1
})
slider.use(
new AccessibilityPlugin({
useKeyboardNavigation: true,
useFocusManagement: true,
labels: {
root: "Featured products carousel",
pagination: "Featured products pagination",
previousSlide: "Show previous product",
nextSlide: "Show next product",
slide: (slideNumber, totalSlides) =>
`Product ${slideNumber} of ${totalSlides}`,
page: pageNumber => `Go to page ${pageNumber}`,
liveRegionSingle: (slideNumber, totalSlides) =>
`Showing product ${slideNumber} of ${totalSlides}`,
liveRegionRange: (firstSlideNumber, lastSlideNumber, totalSlides) =>
`Showing products ${firstSlideNumber} to ${lastSlideNumber} of ${totalSlides}`,
liveRegionFallback: totalSlides =>
`Carousel updated. ${totalSlides} slides available.`
}
})
)
slider.init()- Accessible labels for arrows, dots, and slides
- A live region for screen reader announcements
- Keyboard navigation on the slider root
- Focus alignment with the active page when
useFocusManagementis enabled
Enables arrow-key navigation on the slider root.
Moves focus to the active pagination control when appropriate.
Overrides all accessible strings, including slide labels and live region messages.
- The plugin root is inherited automatically from the host slider.
- Attach before calling
slider.init(). - Works with both regular sliders and stories-enhanced sliders.
- If arrows or dots are missing from the markup, the plugin cannot label them.
BrickSlider Stories turns a regular slider into a story-style modal flow with timed progress, video awareness, and pause/resume interactions.
npm install @sixsrc/brick-slider @sixsrc/brick-slider-storiesKeep the stories controls in your HTML markup. The plugin controls state and behavior, but the progress rail, pause indicator, close button, and mute button should stay explicitly available in the DOM.
<button id="open-stories" type="button">Open Stories</button>
<div id="stories-slider">
<button class="bs-arrow bs-prev" type="button">Prev</button>
<button class="bs-arrow bs-next" type="button">Next</button>
<div class="bs-track">
<div class="bs-container">
<div class="bs-slide">Story 01</div>
<div class="bs-slide">Story 02</div>
<div class="bs-slide">Story 03</div>
</div>
<ul class="bs-stories-progress">
<li class="bs-stories-progress-item">
<span class="bs-stories-progress-bar"></span>
</li>
</ul>
<button class="bs-stories-pause-indicator" type="button">
<span class="bs-stories-pause">Pause</span>
<span class="bs-stories-play hidden">Play</span>
</button>
</div>
</div>
<div class="bs-stories-layer hidden">
<div class="bs-stories-backdrop"></div>
<button class="bs-stories-close" type="button">Close</button>
<button class="bs-stories-mute" type="button">Mute</button>
</div>import { BrickSlider } from "@sixsrc/brick-slider"
import StoriesPlugin from "@sixsrc/brick-slider-stories"
const slider = new BrickSlider("#stories-slider", {
slidesPerView: 1,
slidesPerPage: 1,
useLoop: false
})
slider.use(
new StoriesPlugin({
trigger: "#open-stories",
duration: 5000,
maxVideoDuration: 60000,
maxStories: 10,
closeOnEnd: true,
pauseOnHover: true,
useMuted: true
})
)
slider.init()The Stories plugin forces its own story flow and ignores these core slider options if they are present on the host instance:
slidesPerViewslidesPerPagegapslideSizesscreensresponsiveuseLoopuseDragFreeuseAutoHeight
In practice, stories always runs as a single-story flow with its own internal navigation rules.
| Option | Description |
|---|---|
trigger |
Element or selector that opens the stories modal |
duration |
Duration in ms for non-video stories |
maxVideoDuration |
Maximum video duration before clamping to this value |
maxStories |
Maximum number of progress bars the UI should represent |
pauseOnHover |
Pauses the story on pointer hover (desktop) |
closeOnEnd |
Closes the modal after the last story finishes |
useMuted |
Starts video stories muted and enables the mute toggle |
Spaceโ pause/resume the current storyEscapeโ close the stories dialog- Desktop: pointer hover pauses when
pauseOnHoveris enabled - Touch: press and hold to pause, release to resume
Fired when the stories flow is opened. Payload: rootSelector.
slider.on("storiesOpened", rootSelector => {
console.log(rootSelector)
})Fired when the stories modal is fully mounted and ready. Payload: rootSelector.
slider.on("storiesMounted", rootSelector => {
console.log(rootSelector)
})Fired when the stories flow is closed. Payload: rootSelector.
slider.on("storiesClosed", rootSelector => {
console.log(rootSelector)
})Markup order โ keep this structure: optional arrows โ .bs-track โ .bs-container as first child โ stories-specific elements after .bs-container โ .bs-stories-layer outside the slider root.
Multiple videos per story โ only the first video drives timed progress, autoplay, and mute state.
npm install @sixsrc/brick-slider @sixsrc/brick-slider-tailwind tailwindcssAdd the plugin and preset to your main stylesheet:
@import "tailwindcss";
@import "@sixsrc/brick-slider-tailwind/preset.css";
@plugin "@sixsrc/brick-slider-tailwind";If you want to keep the BrickSlider markup classes but do not want to run Tailwind in the project, import the structural CSS shipped by the Tailwind package:
import "@sixsrc/brick-slider-tailwind/brick-slider.css"Or with a plain stylesheet:
@import "@sixsrc/brick-slider-tailwind/brick-slider.css";If you are using BrickSlider directly in HTML or alongside Tailwind loaded from a CDN, load the structural CSS too:
<link
rel="stylesheet"
href="https://unpkg.com/@sixsrc/brick-slider-tailwind@1.0.9/brick-slider.css"
/><link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@sixsrc/brick-slider-tailwind@1.0.9/brick-slider.css"
/>This file provides the structural layout for the standard BrickSlider markup (bs-track, bs-container, bs-slide, bs-dots, bs-progress, and related helpers) without forcing a visual theme.
BrickSlider does not force the visual treatment of active slides or active dots. Those states are intentionally left for you to theme.
Example:
.active > .bs-content {
@apply border border-violet-800 rounded-lg;
}
.bs-dot--active {
@apply bg-violet-800 border border-violet-800;
}If you are not using Tailwind, the same idea applies with plain CSS:
.active > .bs-content {
border: 1px solid #5b21b6;
border-radius: 0.5rem;
}
.bs-dot--active {
background: #5b21b6;
border: 1px solid #5b21b6;
}For the Stories plugin, the structural classes are provided by the package, but the visual progress theme is still yours to control.
Tailwind example:
.bs-stories-progress-item {
@apply bg-white/20;
}
.bs-stories-progress-item--active {
@apply bg-white/35;
}
.bs-stories-progress-item--completed {
@apply bg-white/45;
}
.bs-stories-progress-bar {
@apply bg-white;
}Plain CSS example:
.bs-stories-progress-item {
background: rgb(255 255 255 / 0.2);
}
.bs-stories-progress-item--active {
background: rgb(255 255 255 / 0.35);
}
.bs-stories-progress-item--completed {
background: rgb(255 255 255 / 0.45);
}
.bs-stories-progress-bar {
background: #fff;
}Core
| Class | Description |
|---|---|
bs-track |
Required viewport wrapper |
bs-container |
Required slide row inside bs-track |
bs-slide |
Required slide item inside bs-container |
bs-arrow / bs-prev / bs-next |
Arrow navigation buttons |
bs-pages |
Optional current page output (e.g. 2/5) |
bs-dots / bs-dot |
Optional pagination container and item template |
bs-progress / bs-progress-bar |
Optional progress rail |
bs-hidden |
Utility class used before mount |
bs-peek / bs-peek-sm / bs-peek-lg |
Optional peek spacing variants for bs-track |
bs-auto-height-layout |
Optional helper for auto-height layouts |
Stories
| Class | Description |
|---|---|
bs-stories-progress |
Stories progress rail container |
bs-stories-progress-item |
Stories progress segment |
bs-stories-progress-bar |
Animated bar inside each progress item |
bs-stories-pause-indicator |
Play/pause overlay control |
bs-stories-pause / bs-stories-play |
Pause/play icon or label containers |
bs-stories-layer |
Optional stories overlay layer |
bs-stories-backdrop |
Optional backdrop inside the stories layer |
bs-stories-close |
Close button |
bs-stories-mute |
Mute button for video stories |
BrickSlider is framework-agnostic by design. Instead of maintaining official wrappers, we welcome community-written integration guides.
- ๐ Website: sixsrc.github.io/brickslider
- ๐ฎ Demos: BrickSlider examples
- ๐ Bugs: open a Bug report with a minimal reproduction.
- โจ Features: open a Feature request with the use case and expected API.
- โ Questions: use the Question template for usage or integration doubts.
- ๐ค Contributions: read CONTRIBUTING.md before opening a pull request.
BrickSlider is released under the MIT license. ยฉ 2026 @sixsrc | @malopestorres