Responsive Accessible Carousel Engine with Stories – BrickSlider.js

Category: Javascript , Slider | August 8, 2026
Authorsixsrc
Last UpdateAugust 8, 2026
LicenseMIT
Views31 views
Responsive Accessible Carousel Engine with Stories – BrickSlider.js

BrickSlider is a TypeScript-first carousel engine that creates responsive sliders, draggable content rails, and Instagram-like stories.

Slides can use equal or variable widths, custom breakpoint rules, touch dragging, looping, free dragging, and automatic height adjustment.

Motion runs through the Web Animations API, while navigation, pagination, progress indicators, and visual states stay accessible through regular HTML and CSS.

Features:

  • Responsive layouts with configurable slides per view and page.
  • Touch and pointer dragging for desktop and mobile carousels.
  • Variable slide widths for mixed-size cards and content panels.
  • Custom breakpoints for layout changes across screen sizes.
  • Infinite looping and free-drag interaction modes.
  • Automatic height adjustment for slides with different content lengths.
  • Plugin-based accessibility and story-style carousel features.
  • TypeScript types for core configuration, events, and plugins.
  • Tailwind utilities plus plain CSS structural styles.

How to Use It:

Installation

BrickSlider supports browser bundles for plain HTML projects and ES modules for bundler-based projects. The browser version needs structural slider CSS in addition to the core JavaScript.

For a direct CDN setup, load the structural CSS first and the browser bundle after it.

<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/@sixsrc/[email protected]/lib/brick-slider.css"
/>
<script src="https://cdn.jsdelivr.net/npm/@sixsrc/[email protected]/lib/brick-slider.browser.min.js"></script>

For npm projects, install the core package:

npm install @sixsrc/brick-slider

Add the structural style package when you want the supplied BrickSlider layout rules:

npm install @sixsrc/brick-slider @sixsrc/brick-slider-tailwind

Import its plain CSS build in JavaScript:

import "@sixsrc/brick-slider-tailwind/brick-slider.css";

Tailwind projects can install Tailwind and the BrickSlider package together:

npm install @sixsrc/brick-slider @sixsrc/brick-slider-tailwind tailwindcss

Add the preset and plugin to the main stylesheet:

@import "tailwindcss";
@import "@sixsrc/brick-slider-tailwind/preset.css";
@plugin "@sixsrc/brick-slider-tailwind";

Basic Usage

A carousel needs a .bs-track, a .bs-container inside the track, and .bs-slide elements inside the container. Navigation, page counters, dots, and progress elements can be added when the interface needs them.

<div id="featured-slider">
  <button class="bs-arrow bs-prev" type="button">
    Previous
  </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">Product Alpha</div>
      <div class="bs-slide">Product Beta</div>
      <div class="bs-slide">Product Gamma</div>
      <div class="bs-slide">Product Delta</div>
    </div>
  </div>
  <ul class="bs-dots">
    <li>
      <button class="bs-dot" type="button"></button>
    </li>
  </ul>
  <div class="bs-progress">
    <div class="bs-progress-bar"></div>
  </div>
</div>
const { BrickSlider } = window;
const featuredSlider = new BrickSlider("#featured-slider", {
  slidesPerView: 1,
  slidesPerPage: 1,
  gap: 16,
  useTouch: true
});
featuredSlider.init();

ES module projects import the class from the core package:

import { BrickSlider } from "@sixsrc/brick-slider";
const featuredSlider = new BrickSlider("#featured-slider", {
  slidesPerView: 1,
  slidesPerPage: 1,
  gap: 16
});
featuredSlider.init();

Configuration Options

BrickSlider separates visible slide count, pagination movement, spacing, responsive rules, and interaction behavior.

  • gap (number): Sets the space between slides in pixels.
  • initialSlide (number): Selects the active slide when the carousel mounts. Negative values become 0, out-of-range values stop at the last valid slide, and decimal values are normalized to an integer.
  • slidesPerPage (number): Sets how many slides navigation advances for each paginated step.
  • slidesPerView (number): Sets how many slides appear in the viewport.
  • slideSizes (object): Maps individual slide indexes to custom percentage widths.
  • screens (object): Defines custom breakpoint values with xs, sm, md, lg, xl, and 2xl keys.
  • responsive (object): Applies slide counts, page sizes, and custom widths at selected breakpoints.
  • useTouch (boolean): Activates touch and drag interaction.
  • useLoop (boolean): Creates continuous navigation through cloned slides.
  • useDragFree (boolean): Switches from paginated snapping to free dragging.
  • useAutoHeight (boolean): Updates carousel height for the currently visible content.

Responsive configurations can also use useSlidesPerView, useSlidesPerPage, and useSlideSizes flags. Set one of these flags to false when a breakpoint should retain the corresponding base setting.

Create Responsive Multi-Item Layouts

The responsive configuration uses named breakpoints from the screens object. Each breakpoint can change visible slides, navigation step size, or individual slide widths.

const resourceSlider = new BrickSlider("#resource-slider", {
  gap: 20,
  slidesPerView: 1,
  slidesPerPage: 1,
  screens: {
    sm: 480,
    md: 768,
    lg: 1024
  },
  responsive: {
    sm: {
      slidesPerView: 2,
      slidesPerPage: 2
    },
    md: {
      slidesPerView: 3,
      slidesPerPage: 3
    },
    lg: {
      slidesPerView: 4,
      slidesPerPage: 4
    }
  }
});
resourceSlider.init();

Mix Different Slide Widths

slideSizes assigns percentage widths by slide index. This works well for layouts with one prominent card beside smaller supporting cards.

const gallerySlider = new BrickSlider("#gallery-slider", {
  slidesPerView: 2,
  slidesPerPage: 1,
  gap: 18,
  slideSizes: {
    0: 65,
    1: 35,
    2: 40,
    3: 60
  }
});
gallerySlider.init();

A breakpoint can replace these widths or disable them with useSlideSizes: false.

const gallerySlider = new BrickSlider("#gallery-slider", {
  slideSizes: {
    0: 65,
    1: 35
  },
  screens: {
    md: 768,
    lg: 1024
  },
  responsive: {
    md: {
      slideSizes: {
        0: 55,
        1: 45
      }
    },
    lg: {
      slidesPerView: 3,
      useSlideSizes: false
    }
  }
});
gallerySlider.init();

Start From A Specific Slide

initialSlide accepts the slide index that should become active during initialization.

const gallerySlider = new BrickSlider("#gallery-slider", {
  initialSlide: 3,
  slidesPerView: 1,
  slidesPerPage: 1
});
gallerySlider.init();

Enable Free Dragging

Standard navigation snaps to carousel pages. useDragFree changes the interaction to continuous dragging.

const logoRail = new BrickSlider("#logo-rail", {
  slidesPerView: 4,
  gap: 24,
  useTouch: true,
  useDragFree: true
});
logoRail.init();

Auto Height

Set useAutoHeight when slide content has noticeably different heights.

const testimonialSlider = new BrickSlider("#testimonial-slider", {
  slidesPerView: 1,
  slidesPerPage: 1,
  useAutoHeight: true
});
testimonialSlider.init();

Styling And Customization

BrickSlider uses bs-* classes for carousel structure and interface elements. The structural CSS handles slider layout while active colors, borders, typography, card surfaces, and other visual details stay in the project stylesheet.

Core CSS classes :

  • bs-track: Viewport wrapper.
  • bs-container: Slide row inside the track.
  • bs-slide: Individual slide.
  • bs-arrow: Shared navigation button class.
  • bs-prev: Previous navigation control.
  • bs-next: Next navigation control.
  • bs-pages: Current page display.
  • bs-dots: Pagination container.
  • bs-dot: Pagination control.
  • bs-progress: Progress rail.
  • bs-progress-bar: Progress indicator.
  • bs-hidden: Utility state used before mount.
  • bs-peek: Standard peek spacing.
  • bs-peek-sm: Smaller peek spacing.
  • bs-peek-lg: Larger peek spacing.
  • bs-auto-height-layout: Helper for auto-height layouts.

BrickSlider adds .bs-dot--active to the current pagination dot. Define its appearance in the project stylesheet.

.bs-dot {
  width: 1.5rem;
  height: 1.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 999px;
  background: transparent;
}
.bs-dot::before {
  content: "";
  width: 0.75rem;
  height: 0.75rem;
  border: 1px solid #94a3b8;
  border-radius: 999px;
}
.bs-dot--active::before {
  background: #334155;
  border-color: #334155;
}

Accessibility Plugin

The optional accessibility package adds ARIA labels, screen reader announcements, keyboard navigation, and focus management to the standard carousel controls.

Install it with the core package:

npm install @sixsrc/brick-slider @sixsrc/brick-slider-accessibility

Attach the plugin before init().

import { BrickSlider } from "@sixsrc/brick-slider";
import AccessibilityPlugin from "@sixsrc/brick-slider-accessibility";
const productSlider = new BrickSlider("#product-slider", {
  slidesPerView: 1,
  slidesPerPage: 1
});
productSlider.use(
  new AccessibilityPlugin({
    useKeyboardNavigation: true,
    useFocusManagement: true
  })
);
productSlider.init();

Its public configuration consists of three areas:

  • useKeyboardNavigation (boolean): Adds arrow-key navigation to the slider root.
  • useFocusManagement (boolean): Aligns focus with the active pagination control when appropriate.
  • labels (object): Replaces accessible names and live-region messages.

Custom labels can match the content shown inside the carousel.

productSlider.use(
  new AccessibilityPlugin({
    useKeyboardNavigation: true,
    useFocusManagement: true,
    labels: {
      root: "New arrivals",
      pagination: "New arrivals pages",
      previousSlide: "Previous products",
      nextSlide: "Next products",
      slide: (number, total) =>
        `Product ${number} of ${total}`,
      page: number =>
        `Go to product page ${number}`,
      liveRegionSingle: (number, total) =>
        `Showing product ${number} of ${total}`,
      liveRegionRange: (first, last, total) =>
        `Showing products ${first} through ${last} of ${total}`,
      liveRegionFallback: total =>
        `${total} products available`
    }
  })
);

Arrow and dot markup must exist if the plugin needs to label those controls.

Create An Instagram-Style Stories Carousel

The Stories plugin changes a regular BrickSlider instance into a timed, single-story modal flow. It supports regular content and video slides, timed progress, pause and resume controls, closing at the final story, and muted video playback.

Install the plugin with the core package:

npm install @sixsrc/brick-slider @sixsrc/brick-slider-stories

Stories need additional controls for the progress segments, pause state, modal layer, close action, and video mute action.

<button id="show-stories" type="button">
  View Stories
</button>
<div id="stories">
  <button class="bs-arrow bs-prev" type="button">
    Previous
  </button>
  <button class="bs-arrow bs-next" type="button">
    Next
  </button>
  <div class="bs-track">
    <div class="bs-container">
      <div class="bs-slide">Story One</div>
      <div class="bs-slide">Story Two</div>
      <div class="bs-slide">Story Three</div>
    </div>
    <div class="bs-stories-progress">
      <button
        class="bs-stories-progress-item"
        type="button"
      >
        <span class="bs-stories-progress-bar"></span>
      </button>
    </div>
    <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>

Attach StoriesPlugin before mounting the slider.

import { BrickSlider } from "@sixsrc/brick-slider";
import StoriesPlugin from "@sixsrc/brick-slider-stories";
const stories = new BrickSlider("#stories", {
  slidesPerView: 1,
  slidesPerPage: 1
});
stories.use(
  new StoriesPlugin({
    trigger: "#show-stories",
    duration: 5000,
    maxVideoDuration: 60000,
    maxStories: 10,
    pauseOnHover: true,
    closeOnEnd: true,
    useMuted: true
  })
);
stories.init();

Stories Plugin Options

  • trigger: Sets the element or selector that opens the story modal.
  • duration: Sets the display time in milliseconds for non-video stories.
  • maxVideoDuration: Caps the duration used for a video story.
  • maxStories: Sets the maximum number of progress segments represented in the interface.
  • pauseOnHover: Pauses progress during pointer hover on desktop.
  • closeOnEnd: Closes the story interface after the final story.
  • useMuted: Starts video stories muted and activates mute controls.

Stories use their own single-item navigation behavior. The plugin ignores these core settings on its host slider:

  • slidesPerView
  • slidesPerPage
  • gap
  • slideSizes
  • screens
  • responsive
  • useLoop
  • useDragFree
  • useAutoHeight

Keyboard and pointer interactions include:

  • Space pauses or resumes the current story.
  • Escape closes the story interface.
  • Pointer hover pauses playback when pauseOnHover is active.
  • Touch press and hold pauses playback until release.

Only the first video inside a story controls its timed progress and mute state.

Style The Stories Progress Indicator

The Stories classes supply the required structural hooks. Define colors and visual states in project CSS.

.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;
}

Stories-specific classes include:

  • bs-stories-progress: Progress rail.
  • bs-stories-progress-item: Individual progress segment.
  • bs-stories-progress-bar: Animated progress bar.
  • bs-stories-pause-indicator: Pause and play control.
  • bs-stories-pause: Pause-state content.
  • bs-stories-play: Play-state content.
  • bs-stories-layer: Modal overlay layer.
  • bs-stories-backdrop: Backdrop.
  • bs-stories-close: Close control.
  • bs-stories-mute: Video mute control.

API Methods

The core instance exposes methods for initialization, navigation, cleanup, and plugin registration.

// Mount the slider and initialize its interactions.
slider.init();
// Move forward one page.
slider.next();
// Move backward one page.
slider.prev();
// Navigate to a specific page index.
slider.goTo(2);
// Attach a plugin before initialization.
slider.use(plugin);
// Tear down the slider and restore its original markup.
slider.destroy();

Events

Core events cover initialization, page changes, and teardown.

// Fires when the slider DOM and layout are ready.
slider.on("mounted", function (rootSelector) {
  console.log(rootSelector);
});
// Fires when the active page changes.
slider.on("slideChange", function (payload) {
  console.log(payload.slideIndex);
  console.log(payload.activePage);
});
// Fires after the slider has been destroyed.
slider.on("destroyed", function (rootSelector) {
  console.log(rootSelector);
});

The Stories plugin adds lifecycle events for its modal flow.

// Fires when the Stories flow opens.
slider.on("storiesOpened", function (rootSelector) {
  console.log(rootSelector);
});
// Fires when the Stories interface finishes mounting.
slider.on("storiesMounted", function (rootSelector) {
  console.log(rootSelector);
});
// Fires when the Stories flow closes.
slider.on("storiesClosed", function (rootSelector) {
  console.log(rootSelector);
});

React Integration

BrickSlider does not require a React wrapper. Mount the core instance after the component reaches the DOM, then destroy it during effect cleanup.

import { useEffect, useRef } from "react";
import { BrickSlider } from "@sixsrc/brick-slider";
export function ArticleCarousel() {
  const rootRef = useRef(null);
  const sliderId = "article-carousel";
  useEffect(() => {
    if (!rootRef.current) return;
    const slider = new BrickSlider(`#${sliderId}`, {
      slidesPerView: 1,
      slidesPerPage: 1,
      gap: 16
    });
    slider.init();
    return () => {
      slider.destroy();
    };
  }, []);
  return (
    <div id={sliderId} ref={rootRef}>
      <button className="bs-arrow bs-prev" type="button">
        Previous
      </button>
      <button className="bs-arrow bs-next" type="button">
        Next
      </button>
      <div className="bs-track">
        <div className="bs-container">
          <div className="bs-slide">Article One</div>
          <div className="bs-slide">Article Two</div>
          <div className="bs-slide">Article Three</div>
        </div>
      </div>
    </div>
  );
}

Alternatives:

FAQs:

Q: Does BrickSlider require Tailwind CSS?
A: No. Tailwind support comes from a separate package. Plain CSS projects can load brick-slider.css from @sixsrc/brick-slider-tailwind and style the visual states themselves.

Q: Can BrickSlider run directly in a normal HTML page?
A: Yes. Load the structural CSS and the browser JavaScript bundle, then create the carousel through window.BrickSlider.

Q: Why does my BrickSlider carousel have no layout or styling?
A: Check that the required structural CSS exists and that the markup contains .bs-track, .bs-container, and .bs-slide. The core JavaScript does not supply a complete visual theme.

Q: Does BrickSlider support accessibility features?
A: The separate accessibility plugin adds ARIA labels, screen reader announcements, arrow-key navigation, and optional focus management. Attach the plugin before calling init().

You Might Be Interested In:


Leave a Reply