Shadix.Components.Carousel (shadix v0.0.1)

Copy Markdown View Source

A horizontal carousel built on native CSS scroll-snap and a small LiveView hook.

Unlike the React original (which wraps Embla), this v1 is a pure CSS scroll-snap carousel: the content track is an overflow-x-auto flex row with snap-x snap-mandatory, and each item is a full-width snap-start child. Scrolling, momentum, and snapping are entirely native to the browser, so there is no JS layout/animation loop.

The ShadixCarousel hook (assets/ts/carousel.ts) only wires the previous/next buttons: clicking them scrolls the content element by one item (its clientWidth) left or right with smooth behaviour, and the hook toggles the buttons' disabled state at the start/end of the track (and on scroll / resize).

Simplifications vs. the original

  • Horizontal only. No orientation="vertical".
  • No drag/pointer physics. You can still drag/flick on touch devices via native scrolling, but there is no Embla-style mouse-drag inertia.
  • No autoplay, no loop, no programmatic setApi/opts/plugins.
  • One-item paging. Prev/next scroll by exactly one viewport width (one full-basis item) rather than honouring multi-item slidesToScroll.
  • Keyboard arrows are not bound (the React version listens for Left/Right); rely on the focusable scroll container instead.

The content track and buttons are linked by data-carousel-prev / data-carousel-next markers and a data-carousel-content marker so the hook can find them from the root wrapper without ids.

Summary

Functions

Renders the carousel root: a relative wrapper carrying the ShadixCarousel hook.

The scrollable track. A horizontal flex row with mandatory x scroll-snap and a hidden scrollbar.

A single slide. Full-basis, non-growing/shrinking, snapping to its start edge.

The "next" control: a round, absolutely-positioned icon button.

The "previous" control: a round, absolutely-positioned icon button.

Functions

carousel(assigns)

Renders the carousel root: a relative wrapper carrying the ShadixCarousel hook.

Compose carousel_content/1 (with carousel_item/1 children) and the carousel_previous/1 / carousel_next/1 buttons inside it. The hook finds the content track and buttons by their data-carousel-* markers, so they may appear anywhere within this wrapper.

Attributes

  • id (:string) (required)
  • class (:string) - Defaults to nil.
  • Global attributes are accepted.

Slots

  • inner_block (required)