Skip to content

[Toolkit][Shadcn] Add carousel recipe - #3853

Open
ker0x wants to merge 1 commit into
symfony:3.xfrom
ker0x:feat/toolkit-shadcn-carousel
Open

ker0x wants to merge 1 commit into
symfony:3.xfrom
ker0x:feat/toolkit-shadcn-carousel

Conversation

@ker0x

@ker0x ker0x commented Sep 9, 2026

Copy link
Copy Markdown
Contributor
Q A
Bug fix? no
New feature? yes
Deprecations? no
Documentation? yes
Issues Part of #3233
License MIT

Adds the carousel recipe to the Shadcn kit.

<twig:Carousel orientation="horizontal | vertical" align="start | center | end" loop>
    <twig:Carousel:Content>
        <twig:Carousel:Item>...</twig:Carousel:Item>
        <twig:Carousel:Item>...</twig:Carousel:Item>
        <twig:Carousel:Item>...</twig:Carousel:Item>
    </twig:Carousel:Content>
    <twig:Carousel:Previous />
    <twig:Carousel:Next />
</twig:Carousel>

Embla

Upstream shadcn builds Carousel on Embla Carousel, an npm dependency. No Toolkit recipe ships one — every controller in the kit imports only @hotwired/stimulus — so the behaviour is reimplemented as a self-contained carousel controller: a flex track translated with a CSS transform, whose snap positions are measured from the rendered slides rather than configured, so any basis-* utility on a Carousel:Item works with no extra wiring, and they are re-measured on resize.

Consequences for the public API:

  • Embla's opts become props on Carousel: align and loop.
  • Embla's Autoplay plugin becomes an autoplay prop (delay in ms). The upstream "Plugins" section is therefore documented as Autoplay.
  • Embla's setApi becomes a carousel:select event carrying { index, count }. The recipe ships a small carousel-display controller that renders the current position from it, mirroring what slider does with slider-display.

Notes

  • Positions are expressed along the logical axis, so the same math drives horizontal, vertical and RTL carousels; only the sign of the applied transform changes. Directional classes are logical (-ms-4, ps-4, -start-12, -end-12), which also keeps the "Spacing" example overridable in both directions.
  • Carousel:Previous renders disabled when the carousel does not loop, so the first slide has no enabled → disabled flash on load; the controller then syncs both buttons on every change.
  • Arrow keys follow the carousel axis and the text direction (in RTL, advances).
  • A click that terminates a drag is swallowed, so dragging over a link or a button inside a slide does not activate it.

Testing

Snapshots regenerated; bin/ux-toolkit-kit-lint --fail-on-warning kits/shadcn, twig-cs-fixer, oxfmt and oxlint are clean.

Behaviour driven in headless Chromium against a real Tailwind v4 build of the rendered examples, with no console errors:

Result
LTR / vertical / RTL stepping correct transforms and snap counts per orientation
prev/next disabled sync disabled at both ends, both enabled in between
arrow keys follow the axis and the text direction
pointer drag works on all three axes, with rubber-band and momentum snap
click after drag swallowed
resize re-measures and stays on the same slide
loop + autoplay wraps, pauses on hover/focus, resets after interaction
disconnect/reconnect no leaked timers or listeners

Companion PR

Needed, since the recipe ships Stimulus controllers and new Tailwind classes: register carousel / carousel-display in assets/toolkit-shadcn.js and rebuild the CSS on symfony/ux.symfony.com. Will link it here.

@ker0x
ker0x requested a review from Kocal as a code owner September 9, 2026 09:24
@carsonbot carsonbot added Status: Needs Review Needs to be reviewed Documentation Improvements or additions to documentation Feature New Feature Toolkit labels Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Documentation Improvements or additions to documentation Feature New Feature Status: Needs Review Needs to be reviewed Toolkit

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants