# `PhiaUi.Components.Carousel`
[🔗](https://github.com/charlenopires/PhiaUI/blob/v0.1.17/lib/phia_ui/components/media/carousel.ex#L1)

Carousel component with touch swipe, button navigation, and keyboard support.

Follows the shadcn/ui Carousel anatomy adapted for Phoenix LiveView.
The `PhiaCarousel` vanilla-JS hook manages CSS `transform`-based sliding,
touch/swipe detection, keyboard navigation (arrow keys), and optional loop
behaviour. Zero npm dependencies.

## When to use

- Hero banner with rotating promotional images
- Product image gallery (multiple photos of the same item)
- Onboarding walkthrough (step-by-step screens)
- Testimonial rotator
- Vertical announcement ticker

## Anatomy

| Component             | Element  | Purpose                                        |
|-----------------------|----------|------------------------------------------------|
| `carousel/1`          | `div`    | Root container — mounts the `PhiaCarousel` hook|
| `carousel_content/1`  | `div`    | Flex track that holds all slides side-by-side  |
| `carousel_item/1`     | `div`    | Individual slide (`min-w-full shrink-0`)        |
| `carousel_previous/1` | `button` | Navigate to the previous slide                 |
| `carousel_next/1`     | `button` | Navigate to the next slide                     |

## Basic horizontal carousel

    <.carousel id="hero-banner">
      <.carousel_content>
        <.carousel_item>
          <img src="/images/promo-1.jpg" alt="Summer sale" class="w-full object-cover" />
        </.carousel_item>
        <.carousel_item>
          <img src="/images/promo-2.jpg" alt="New arrivals" class="w-full object-cover" />
        </.carousel_item>
        <.carousel_item>
          <img src="/images/promo-3.jpg" alt="Free shipping" class="w-full object-cover" />
        </.carousel_item>
      </.carousel_content>
      <.carousel_previous />
      <.carousel_next />
    </.carousel>

## Looping vertical carousel

    <.carousel id="announcements" orientation="vertical" loop={true}>
      <.carousel_content>
        <.carousel_item class="h-12 flex items-center">
          Maintenance window scheduled for Sunday 2 AM UTC
        </.carousel_item>
        <.carousel_item class="h-12 flex items-center">
          v2.4.0 released — see the changelog
        </.carousel_item>
      </.carousel_content>
      <.carousel_previous />
      <.carousel_next />
    </.carousel>

## Carousel with dot indicator slot

    <.carousel id="product-gallery">
      <.carousel_content>
        <.carousel_item :for={img <- @product_images}>
          <img src={img.url} alt={img.alt} class="w-full rounded-lg object-cover" />
        </.carousel_item>
      </.carousel_content>
      <.carousel_previous />
      <.carousel_next />
      <:indicators>
        <button
          :for={{_img, i} <- Enum.with_index(@product_images)}
          data-index={i}
          class="h-2 w-2 rounded-full bg-muted data-[active]:bg-primary"
        />
      </:indicators>
    </.carousel>

## Accessibility

- The root element has `role="region"` and `aria-label="carousel"`
- Each slide has `role="group"` and `aria-roledescription="slide"`
- Navigation buttons have `aria-label="Previous slide"` / `"Next slide"`
- The root is focusable (`tabindex="0"`) so arrow-key navigation works
  without a mouse

## Hook setup

    mix phia.add carousel   # copies hooks/carousel.js to your project

    # app.js
    import PhiaCarousel from "./hooks/carousel"
    let liveSocket = new LiveSocket("/live", Socket, {
      hooks: { PhiaCarousel }
    })

# `carousel`

Renders the carousel root container.

Mounts the `PhiaCarousel` hook and communicates configuration via `data-*`
attributes. The root is focusable (`tabindex="0"`) so keyboard users can
navigate slides with arrow keys without any additional setup.

`role="region"` + `aria-label="carousel"` ensures the landmark is announced
correctly by screen readers.

## Attributes

* `id` (`:string`) - Unique carousel ID. The `PhiaCarousel` hook uses this to identify the
  instance and store its current slide index in hook state.

  Defaults to `"carousel"`.
* `orientation` (`:string`) - Carousel slide direction:
  - `"horizontal"` — slides left/right (default, most common)
  - `"vertical"`   — slides up/down (e.g. announcement ticker)
  The hook reads `data-orientation` to set the correct transform axis.

  Defaults to `"horizontal"`. Must be one of `"horizontal"`, or `"vertical"`.
* `loop` (`:boolean`) - When `true`, navigating past the last slide wraps to the first (and
  navigating before the first wraps to the last). The hook reads `data-loop`.

  Defaults to `false`.
* `class` (`:string`) - Additional CSS classes for the root div. Defaults to `nil`.
* Global attributes are accepted. HTML attributes forwarded to the root div.
## Slots

* `inner_block` (required) - `carousel_content/1` and navigation sub-components.
* `indicators` - Optional dot indicator buttons rendered at the bottom of the carousel.
  The `PhiaCarousel` hook can toggle a `data-active` attribute on the active
  indicator. Use `data-[active]:bg-primary` Tailwind variant to style it.

# `carousel_content`

Renders the carousel track container.

The `data-carousel-track` attribute is used by the `PhiaCarousel` hook to
locate and animate this element. The hook updates `style.transform` on this
element directly to translate between slides.

`transition-transform duration-300 ease-in-out` provides the slide animation.
Do not remove these classes unless you want an instant snap transition.

## Attributes

* `class` (`:string`) - Additional CSS classes for the track div. Defaults to `nil`.
* Global attributes are accepted. HTML attributes forwarded to the track div (the element that receives `transform`).
## Slots

* `inner_block` (required) - `carousel_item/1` slide children.

# `carousel_item`

Renders an individual carousel slide.

`min-w-full shrink-0` ensures each slide occupies exactly 100% of the track
width (or height for vertical carousels), preventing any bleeding between
slides.

`role="group"` and `aria-roledescription="slide"` allow screen readers to
announce "Slide 1 of 3" when the user navigates via keyboard.

## Attributes

* `class` (`:string`) - Additional CSS classes for the slide div. Defaults to `nil`.
* Global attributes are accepted. HTML attributes forwarded to the slide div.
## Slots

* `inner_block` (required) - Slide content — images, cards, text, etc.

# `carousel_next`

Renders the next-slide navigation button.

The `data-carousel-next` attribute is used by the `PhiaCarousel` hook to
attach a click listener and manage the `disabled` attribute. When `loop`
is `false` and the carousel is at the last slide, the hook sets `disabled`
on this button to prevent forward navigation.

Override the default `›` icon by placing content in the `:inner_block` slot.

## Attributes

* `class` (`:string`) - Additional CSS classes for the button element. Defaults to `nil`.
* Global attributes are accepted. HTML attributes forwarded to the `<button>` element.
## Slots

* `inner_block` - Button content — defaults to the right-pointing single-guillemet character `›`.

# `carousel_previous`

Renders the previous-slide navigation button.

The `data-carousel-prev` attribute is used by the `PhiaCarousel` hook to
attach a click listener and manage the `disabled` attribute. When `loop`
is `false` and the carousel is at the first slide, the hook sets
`disabled` on this button to prevent backward navigation.

Override the default `‹` icon by placing content in the `:inner_block` slot.

## Attributes

* `class` (`:string`) - Additional CSS classes for the button element. Defaults to `nil`.
* Global attributes are accepted. HTML attributes forwarded to the `<button>` element.
## Slots

* `inner_block` - Button content — defaults to the left-pointing single-guillemet character `‹`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
