---
title: Carousel
description: Scrollable container that cycles through children — carousel, reel, or marquee.
icon: rectangle-history
---

import { ComponentPreview } from '/snippets/component-preview.mdx'

Carousel cycles through content — slides, cards, images, anything. Each direct child becomes one slide. The same component handles interactive slideshows (arrows, dots, swipe), auto-advancing reels, and continuously scrolling marquees, all through configuration.

## Basic Usage

One slide visible at a time. Drag to navigate, or use the arrow buttons that appear on each side. Dots below show your position in the sequence:

<ComponentPreview json={{"view":{"cssClass":"w-full","type":"Carousel","visible":1,"gap":16,"direction":"left","loop":true,"autoAdvance":0,"continuous":false,"speed":2,"effect":"slide","dimInactive":false,"showControls":true,"controlsPosition":"outside","showDots":true,"pauseOnHover":true,"align":"start","slidesToScroll":1,"drag":true,"children":[{"cssClass":"bg-blue-500 rounded-lg","type":"Div","style":{"height":"160px"}},{"cssClass":"bg-emerald-500 rounded-lg","type":"Div","style":{"height":"160px"}},{"cssClass":"bg-violet-500 rounded-lg","type":"Div","style":{"height":"160px"}},{"cssClass":"bg-amber-500 rounded-lg","type":"Div","style":{"height":"160px"}}]}}} playground=" ">
<CodeGroup>
```python icon="python"
from prefab_ui.components import Carousel, Div

with Carousel(show_dots=True, css_class="w-full"):
    Div(css_class="bg-blue-500 rounded-lg", style={"height": "160px"})
    Div(css_class="bg-emerald-500 rounded-lg", style={"height": "160px"})
    Div(css_class="bg-violet-500 rounded-lg", style={"height": "160px"})
    Div(css_class="bg-amber-500 rounded-lg", style={"height": "160px"})
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "w-full",
    "type": "Carousel",
    "visible": 1,
    "gap": 16,
    "direction": "left",
    "loop": true,
    "autoAdvance": 0,
    "continuous": false,
    "speed": 2,
    "effect": "slide",
    "dimInactive": false,
    "showControls": true,
    "controlsPosition": "outside",
    "showDots": true,
    "pauseOnHover": true,
    "align": "start",
    "slidesToScroll": 1,
    "drag": true,
    "children": [
      {
        "cssClass": "bg-blue-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      },
      {
        "cssClass": "bg-emerald-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      },
      {
        "cssClass": "bg-violet-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      },
      {
        "cssClass": "bg-amber-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

## Visibility

The `visible` parameter controls how many slides appear at once. It accepts integers and floats, each with different behavior.

### Multiple Slides

Set `visible` to a whole number to show that many slides simultaneously. The carousel advances through any remaining slides that don't fit. Use `gap` to add spacing between them:

<ComponentPreview json={{"view":{"cssClass":"w-full","type":"Carousel","visible":3.0,"gap":16,"direction":"left","loop":true,"autoAdvance":0,"continuous":false,"speed":2,"effect":"slide","dimInactive":false,"showControls":true,"controlsPosition":"outside","showDots":true,"pauseOnHover":true,"align":"start","slidesToScroll":1,"drag":true,"children":[{"cssClass":"bg-blue-500 rounded-lg","type":"Div","style":{"height":"120px"}},{"cssClass":"bg-emerald-500 rounded-lg","type":"Div","style":{"height":"120px"}},{"cssClass":"bg-violet-500 rounded-lg","type":"Div","style":{"height":"120px"}},{"cssClass":"bg-amber-500 rounded-lg","type":"Div","style":{"height":"120px"}},{"cssClass":"bg-purple-500 rounded-lg","type":"Div","style":{"height":"120px"}},{"cssClass":"bg-red-500 rounded-lg","type":"Div","style":{"height":"120px"}}]}}} playground=" ">
<CodeGroup>
```python icon="python"
from prefab_ui.components import Carousel, Div

with Carousel(visible=3, gap=16, show_dots=True, css_class="w-full"):
    Div(css_class="bg-blue-500 rounded-lg", style={"height": "120px"})
    Div(css_class="bg-emerald-500 rounded-lg", style={"height": "120px"})
    Div(css_class="bg-violet-500 rounded-lg", style={"height": "120px"})
    Div(css_class="bg-amber-500 rounded-lg", style={"height": "120px"})
    Div(css_class="bg-purple-500 rounded-lg", style={"height": "120px"})
    Div(css_class="bg-red-500 rounded-lg", style={"height": "120px"})
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "w-full",
    "type": "Carousel",
    "visible": 3.0,
    "gap": 16,
    "direction": "left",
    "loop": true,
    "autoAdvance": 0,
    "continuous": false,
    "speed": 2,
    "effect": "slide",
    "dimInactive": false,
    "showControls": true,
    "controlsPosition": "outside",
    "showDots": true,
    "pauseOnHover": true,
    "align": "start",
    "slidesToScroll": 1,
    "drag": true,
    "children": [
      {
        "cssClass": "bg-blue-500 rounded-lg",
        "type": "Div",
        "style": {"height": "120px"}
      },
      {
        "cssClass": "bg-emerald-500 rounded-lg",
        "type": "Div",
        "style": {"height": "120px"}
      },
      {
        "cssClass": "bg-violet-500 rounded-lg",
        "type": "Div",
        "style": {"height": "120px"}
      },
      {
        "cssClass": "bg-amber-500 rounded-lg",
        "type": "Div",
        "style": {"height": "120px"}
      },
      {
        "cssClass": "bg-purple-500 rounded-lg",
        "type": "Div",
        "style": {"height": "120px"}
      },
      {
        "cssClass": "bg-red-500 rounded-lg",
        "type": "Div",
        "style": {"height": "120px"}
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

### Peek

A decimal value for `visible` shows partial slides at the edges. `visible=1.3` means "show 1.3 slides" — one full slide plus 30% of the next one peeking in from the side:

<ComponentPreview json={{"view":{"cssClass":"w-full","type":"Carousel","visible":1.3,"gap":16,"direction":"left","loop":true,"autoAdvance":0,"continuous":false,"speed":2,"effect":"slide","dimInactive":false,"showControls":true,"controlsPosition":"outside","showDots":true,"pauseOnHover":true,"align":"center","slidesToScroll":1,"drag":true,"children":[{"cssClass":"bg-blue-500 rounded-lg","type":"Div","style":{"height":"160px"}},{"cssClass":"bg-emerald-500 rounded-lg","type":"Div","style":{"height":"160px"}},{"cssClass":"bg-violet-500 rounded-lg","type":"Div","style":{"height":"160px"}},{"cssClass":"bg-amber-500 rounded-lg","type":"Div","style":{"height":"160px"}}]}}} playground=" ">
<CodeGroup>
```python icon="python"
from prefab_ui.components import Carousel, Div

with Carousel(visible=1.3, show_dots=True, align="center", css_class="w-full"):
    Div(css_class="bg-blue-500 rounded-lg", style={"height": "160px"})
    Div(css_class="bg-emerald-500 rounded-lg", style={"height": "160px"})
    Div(css_class="bg-violet-500 rounded-lg", style={"height": "160px"})
    Div(css_class="bg-amber-500 rounded-lg", style={"height": "160px"})
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "w-full",
    "type": "Carousel",
    "visible": 1.3,
    "gap": 16,
    "direction": "left",
    "loop": true,
    "autoAdvance": 0,
    "continuous": false,
    "speed": 2,
    "effect": "slide",
    "dimInactive": false,
    "showControls": true,
    "controlsPosition": "outside",
    "showDots": true,
    "pauseOnHover": true,
    "align": "center",
    "slidesToScroll": 1,
    "drag": true,
    "children": [
      {
        "cssClass": "bg-blue-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      },
      {
        "cssClass": "bg-emerald-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      },
      {
        "cssClass": "bg-violet-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      },
      {
        "cssClass": "bg-amber-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

### Align

The `align` parameter controls where the active slide sits in the viewport. It only has a visible effect when `visible` is a non-integer (peek) or when showing multiple slides — with `visible=1` every alignment looks the same since the slide fills the viewport.

- `"start"` (default) — active slide flush to the leading edge. Peek appears on the trailing side only.
- `"center"` — active slide centered. Peek appears equally on both sides.
- `"end"` — active slide flush to the trailing edge. Peek appears on the leading side only.

### Dim Inactive

Reduce the opacity of slides that aren't in focus. This draws the eye to the active slide while still showing what's around it. Pairs naturally with peek:

<ComponentPreview json={{"view":{"cssClass":"w-full","type":"Carousel","visible":1.3,"gap":16,"direction":"left","loop":true,"autoAdvance":0,"continuous":false,"speed":2,"effect":"slide","dimInactive":true,"showControls":true,"controlsPosition":"outside","showDots":true,"pauseOnHover":true,"align":"center","slidesToScroll":1,"drag":true,"children":[{"cssClass":"bg-blue-500 rounded-lg","type":"Div","style":{"height":"160px"}},{"cssClass":"bg-emerald-500 rounded-lg","type":"Div","style":{"height":"160px"}},{"cssClass":"bg-violet-500 rounded-lg","type":"Div","style":{"height":"160px"}},{"cssClass":"bg-amber-500 rounded-lg","type":"Div","style":{"height":"160px"}}]}}} playground=" ">
<CodeGroup>
```python icon="python"
from prefab_ui.components import Carousel, Div

with Carousel(visible=1.3, dim_inactive=True, show_dots=True, align="center", css_class="w-full"):
    Div(css_class="bg-blue-500 rounded-lg", style={"height": "160px"})
    Div(css_class="bg-emerald-500 rounded-lg", style={"height": "160px"})
    Div(css_class="bg-violet-500 rounded-lg", style={"height": "160px"})
    Div(css_class="bg-amber-500 rounded-lg", style={"height": "160px"})
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "w-full",
    "type": "Carousel",
    "visible": 1.3,
    "gap": 16,
    "direction": "left",
    "loop": true,
    "autoAdvance": 0,
    "continuous": false,
    "speed": 2,
    "effect": "slide",
    "dimInactive": true,
    "showControls": true,
    "controlsPosition": "outside",
    "showDots": true,
    "pauseOnHover": true,
    "align": "center",
    "slidesToScroll": 1,
    "drag": true,
    "children": [
      {
        "cssClass": "bg-blue-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      },
      {
        "cssClass": "bg-emerald-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      },
      {
        "cssClass": "bg-violet-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      },
      {
        "cssClass": "bg-amber-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

## Transitions

### Fade

Crossfade between slides instead of sliding them. The outgoing slide fades out while the incoming one fades in, with no horizontal movement. Works well for ambient displays or hero images where the sliding motion would be distracting. In fade mode, `gap` is ignored so slides fill the viewport cleanly.

<ComponentPreview json={{"view":{"cssClass":"w-full","type":"Carousel","visible":1.0,"gap":16,"direction":"left","loop":true,"autoAdvance":2000,"continuous":false,"speed":2,"effect":"fade","dimInactive":false,"showControls":false,"controlsPosition":"outside","showDots":true,"pauseOnHover":true,"align":"start","slidesToScroll":1,"drag":true,"children":[{"cssClass":"bg-blue-500 rounded-lg","type":"Div","style":{"height":"160px"}},{"cssClass":"bg-emerald-500 rounded-lg","type":"Div","style":{"height":"160px"}},{"cssClass":"bg-violet-500 rounded-lg","type":"Div","style":{"height":"160px"}}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQ2Fyb3VzZWwsIERpdgoKd2l0aCBDYXJvdXNlbChlZmZlY3Q9ImZhZGUiLCBzaG93X2RvdHM9VHJ1ZSwgYXV0b19hZHZhbmNlPTIwMDAsIHNob3dfY29udHJvbHM9RmFsc2UsIGNzc19jbGFzcz0idy1mdWxsIik6CiAgICBEaXYoY3NzX2NsYXNzPSJiZy1ibHVlLTUwMCByb3VuZGVkLWxnIiwgc3R5bGU9eyJoZWlnaHQiOiAiMTYwcHgifSkKICAgIERpdihjc3NfY2xhc3M9ImJnLWVtZXJhbGQtNTAwIHJvdW5kZWQtbGciLCBzdHlsZT17ImhlaWdodCI6ICIxNjBweCJ9KQogICAgRGl2KGNzc19jbGFzcz0iYmctdmlvbGV0LTUwMCByb3VuZGVkLWxnIiwgc3R5bGU9eyJoZWlnaHQiOiAiMTYwcHgifSkK">
<CodeGroup>
```python icon="python"
from prefab_ui.components import Carousel, Div

with Carousel(effect="fade", show_dots=True, auto_advance=2000, show_controls=False, css_class="w-full"):
    Div(css_class="bg-blue-500 rounded-lg", style={"height": "160px"})
    Div(css_class="bg-emerald-500 rounded-lg", style={"height": "160px"})
    Div(css_class="bg-violet-500 rounded-lg", style={"height": "160px"})
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "w-full",
    "type": "Carousel",
    "visible": 1.0,
    "gap": 16,
    "direction": "left",
    "loop": true,
    "autoAdvance": 2000,
    "continuous": false,
    "speed": 2,
    "effect": "fade",
    "dimInactive": false,
    "showControls": false,
    "controlsPosition": "outside",
    "showDots": true,
    "pauseOnHover": true,
    "align": "start",
    "slidesToScroll": 1,
    "drag": true,
    "children": [
      {
        "cssClass": "bg-blue-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      },
      {
        "cssClass": "bg-emerald-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      },
      {
        "cssClass": "bg-violet-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

### Auto Advance

Set `auto_advance` in milliseconds to cycle slides on a timer. The carousel pauses when the user hovers over it (disable with `pause_on_hover=False`). Loop is on by default, so it cycles forever:

<ComponentPreview json={{"view":{"cssClass":"w-full","type":"Carousel","visible":1,"gap":16,"direction":"left","loop":true,"autoAdvance":2000,"continuous":false,"speed":2,"effect":"slide","dimInactive":false,"showControls":true,"controlsPosition":"outside","showDots":true,"pauseOnHover":true,"align":"start","slidesToScroll":1,"drag":true,"children":[{"cssClass":"bg-violet-500 rounded-lg","type":"Div","style":{"height":"160px"}},{"cssClass":"bg-blue-500 rounded-lg","type":"Div","style":{"height":"160px"}},{"cssClass":"bg-emerald-500 rounded-lg","type":"Div","style":{"height":"160px"}}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQ2Fyb3VzZWwsIERpdgoKd2l0aCBDYXJvdXNlbChhdXRvX2FkdmFuY2U9MjAwMCwgc2hvd19kb3RzPVRydWUsIGNvbnRyb2xzX3Bvc2l0aW9uPSJvdXRzaWRlIiwgY3NzX2NsYXNzPSJ3LWZ1bGwiKToKICAgIERpdihjc3NfY2xhc3M9ImJnLXZpb2xldC01MDAgcm91bmRlZC1sZyIsIHN0eWxlPXsiaGVpZ2h0IjogIjE2MHB4In0pCiAgICBEaXYoY3NzX2NsYXNzPSJiZy1ibHVlLTUwMCByb3VuZGVkLWxnIiwgc3R5bGU9eyJoZWlnaHQiOiAiMTYwcHgifSkKICAgIERpdihjc3NfY2xhc3M9ImJnLWVtZXJhbGQtNTAwIHJvdW5kZWQtbGciLCBzdHlsZT17ImhlaWdodCI6ICIxNjBweCJ9KQo">
<CodeGroup>
```python icon="python"
from prefab_ui.components import Carousel, Div

with Carousel(auto_advance=2000, show_dots=True, controls_position="outside", css_class="w-full"):
    Div(css_class="bg-violet-500 rounded-lg", style={"height": "160px"})
    Div(css_class="bg-blue-500 rounded-lg", style={"height": "160px"})
    Div(css_class="bg-emerald-500 rounded-lg", style={"height": "160px"})
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "w-full",
    "type": "Carousel",
    "visible": 1,
    "gap": 16,
    "direction": "left",
    "loop": true,
    "autoAdvance": 2000,
    "continuous": false,
    "speed": 2,
    "effect": "slide",
    "dimInactive": false,
    "showControls": true,
    "controlsPosition": "outside",
    "showDots": true,
    "pauseOnHover": true,
    "align": "start",
    "slidesToScroll": 1,
    "drag": true,
    "children": [
      {
        "cssClass": "bg-violet-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      },
      {
        "cssClass": "bg-blue-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      },
      {
        "cssClass": "bg-emerald-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

## Controls

### Controls Position

Arrow buttons default to overlaying the slides. Set `controls_position="outside"` to place them outside the viewport — useful when the overlay would obscure content:

<ComponentPreview json={{"view":{"cssClass":"gap-6 w-full","type":"Column","children":[{"content":"Overlay (default)","type":"H3"},{"cssClass":"w-full","type":"Carousel","visible":1,"gap":16,"direction":"left","loop":true,"autoAdvance":0,"continuous":false,"speed":2,"effect":"slide","dimInactive":false,"showControls":true,"controlsPosition":"overlay","showDots":true,"pauseOnHover":true,"align":"start","slidesToScroll":1,"drag":true,"children":[{"cssClass":"bg-blue-500 rounded-lg","type":"Div","style":{"height":"120px"}},{"cssClass":"bg-emerald-500 rounded-lg","type":"Div","style":{"height":"120px"}},{"cssClass":"bg-violet-500 rounded-lg","type":"Div","style":{"height":"120px"}}]},{"content":"Outside","type":"H3"},{"cssClass":"w-full","type":"Carousel","visible":1,"gap":16,"direction":"left","loop":true,"autoAdvance":0,"continuous":false,"speed":2,"effect":"slide","dimInactive":false,"showControls":true,"controlsPosition":"outside","showDots":true,"pauseOnHover":true,"align":"start","slidesToScroll":1,"drag":true,"children":[{"cssClass":"bg-amber-500 rounded-lg","type":"Div","style":{"height":"120px"}},{"cssClass":"bg-purple-500 rounded-lg","type":"Div","style":{"height":"120px"}},{"cssClass":"bg-emerald-500 rounded-lg","type":"Div","style":{"height":"120px"}}]}]}}} playground=" ">
<CodeGroup>
```python icon="python"
from prefab_ui.components import Carousel, Column, Div, H3

with Column(gap=6, css_class="w-full"):
    H3("Overlay (default)")
    with Carousel(show_dots=True, controls_position="overlay", css_class="w-full"):
        Div(css_class="bg-blue-500 rounded-lg", style={"height": "120px"})
        Div(css_class="bg-emerald-500 rounded-lg", style={"height": "120px"})
        Div(css_class="bg-violet-500 rounded-lg", style={"height": "120px"})

    H3("Outside")
    with Carousel(show_dots=True, controls_position="outside", css_class="w-full"):
        Div(css_class="bg-amber-500 rounded-lg", style={"height": "120px"})
        Div(css_class="bg-purple-500 rounded-lg", style={"height": "120px"})
        Div(css_class="bg-emerald-500 rounded-lg", style={"height": "120px"})
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-6 w-full",
    "type": "Column",
    "children": [
      {"content": "Overlay (default)", "type": "H3"},
      {
        "cssClass": "w-full",
        "type": "Carousel",
        "visible": 1,
        "gap": 16,
        "direction": "left",
        "loop": true,
        "autoAdvance": 0,
        "continuous": false,
        "speed": 2,
        "effect": "slide",
        "dimInactive": false,
        "showControls": true,
        "controlsPosition": "overlay",
        "showDots": true,
        "pauseOnHover": true,
        "align": "start",
        "slidesToScroll": 1,
        "drag": true,
        "children": [
          {
            "cssClass": "bg-blue-500 rounded-lg",
            "type": "Div",
            "style": {"height": "120px"}
          },
          {
            "cssClass": "bg-emerald-500 rounded-lg",
            "type": "Div",
            "style": {"height": "120px"}
          },
          {
            "cssClass": "bg-violet-500 rounded-lg",
            "type": "Div",
            "style": {"height": "120px"}
          }
        ]
      },
      {"content": "Outside", "type": "H3"},
      {
        "cssClass": "w-full",
        "type": "Carousel",
        "visible": 1,
        "gap": 16,
        "direction": "left",
        "loop": true,
        "autoAdvance": 0,
        "continuous": false,
        "speed": 2,
        "effect": "slide",
        "dimInactive": false,
        "showControls": true,
        "controlsPosition": "outside",
        "showDots": true,
        "pauseOnHover": true,
        "align": "start",
        "slidesToScroll": 1,
        "drag": true,
        "children": [
          {
            "cssClass": "bg-amber-500 rounded-lg",
            "type": "Div",
            "style": {"height": "120px"}
          },
          {
            "cssClass": "bg-purple-500 rounded-lg",
            "type": "Div",
            "style": {"height": "120px"}
          },
          {
            "cssClass": "bg-emerald-500 rounded-lg",
            "type": "Div",
            "style": {"height": "120px"}
          }
        ]
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

### No Loop

Set `loop=False` to stop at the ends instead of wrapping around. The arrow buttons automatically disappear when there's nowhere left to scroll:

<ComponentPreview json={{"view":{"cssClass":"w-full","type":"Carousel","visible":1,"gap":16,"direction":"left","loop":false,"autoAdvance":0,"continuous":false,"speed":2,"effect":"slide","dimInactive":false,"showControls":true,"controlsPosition":"outside","showDots":true,"pauseOnHover":true,"align":"start","slidesToScroll":1,"drag":true,"children":[{"cssClass":"bg-blue-500 rounded-lg","type":"Div","style":{"height":"160px"}},{"cssClass":"bg-emerald-500 rounded-lg","type":"Div","style":{"height":"160px"}},{"cssClass":"bg-violet-500 rounded-lg","type":"Div","style":{"height":"160px"}}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQ2Fyb3VzZWwsIERpdgoKd2l0aCBDYXJvdXNlbChsb29wPUZhbHNlLCBzaG93X2RvdHM9VHJ1ZSwgY3NzX2NsYXNzPSJ3LWZ1bGwiKToKICAgIERpdihjc3NfY2xhc3M9ImJnLWJsdWUtNTAwIHJvdW5kZWQtbGciLCBzdHlsZT17ImhlaWdodCI6ICIxNjBweCJ9KQogICAgRGl2KGNzc19jbGFzcz0iYmctZW1lcmFsZC01MDAgcm91bmRlZC1sZyIsIHN0eWxlPXsiaGVpZ2h0IjogIjE2MHB4In0pCiAgICBEaXYoY3NzX2NsYXNzPSJiZy12aW9sZXQtNTAwIHJvdW5kZWQtbGciLCBzdHlsZT17ImhlaWdodCI6ICIxNjBweCJ9KQo">
<CodeGroup>
```python icon="python"
from prefab_ui.components import Carousel, Div

with Carousel(loop=False, show_dots=True, css_class="w-full"):
    Div(css_class="bg-blue-500 rounded-lg", style={"height": "160px"})
    Div(css_class="bg-emerald-500 rounded-lg", style={"height": "160px"})
    Div(css_class="bg-violet-500 rounded-lg", style={"height": "160px"})
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "w-full",
    "type": "Carousel",
    "visible": 1,
    "gap": 16,
    "direction": "left",
    "loop": false,
    "autoAdvance": 0,
    "continuous": false,
    "speed": 2,
    "effect": "slide",
    "dimInactive": false,
    "showControls": true,
    "controlsPosition": "outside",
    "showDots": true,
    "pauseOnHover": true,
    "align": "start",
    "slidesToScroll": 1,
    "drag": true,
    "children": [
      {
        "cssClass": "bg-blue-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      },
      {
        "cssClass": "bg-emerald-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      },
      {
        "cssClass": "bg-violet-500 rounded-lg",
        "type": "Div",
        "style": {"height": "160px"}
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

## Direction

Carousels scroll horizontally by default (`direction="left"`). Set `direction="down"` or `direction="up"` for vertical scrolling. The carousel automatically measures the first slide's height to determine the viewport size.

Vertical carousels are great for status feeds, departure boards, or cycling through messages in a fixed-height area:

<ComponentPreview json={{"view":{"cssClass":"gap-6 w-full","type":"Column","children":[{"content":"Vertical with controls","type":"H3"},{"cssClass":"w-full","type":"Carousel","visible":1,"gap":16,"direction":"down","loop":true,"autoAdvance":0,"continuous":false,"speed":2,"effect":"slide","dimInactive":false,"showControls":true,"controlsPosition":"outside","showDots":true,"pauseOnHover":true,"align":"start","slidesToScroll":1,"drag":true,"children":[{"cssClass":"bg-blue-500 rounded-lg","type":"Div","style":{"height":"160px"}},{"cssClass":"bg-emerald-500 rounded-lg","type":"Div","style":{"height":"160px"}},{"cssClass":"bg-violet-500 rounded-lg","type":"Div","style":{"height":"160px"}}]},{"content":"Vertical reel (auto advance)","type":"H3"},{"cssClass":"w-full","type":"Carousel","visible":1,"gap":16,"direction":"down","loop":true,"autoAdvance":2000,"continuous":false,"speed":2,"effect":"slide","dimInactive":false,"showControls":false,"controlsPosition":"outside","showDots":false,"pauseOnHover":true,"align":"start","slidesToScroll":1,"drag":true,"children":[{"cssClass":"bg-blue-500 rounded-lg","type":"Div","style":{"height":"160px"}},{"cssClass":"bg-emerald-500 rounded-lg","type":"Div","style":{"height":"160px"}},{"cssClass":"bg-violet-500 rounded-lg","type":"Div","style":{"height":"160px"}}]}]}}} playground=" ">
<CodeGroup>
```python icon="python"
from prefab_ui.components import Carousel, Column, Div, H3

with Column(gap=6, css_class="w-full"):
    H3("Vertical with controls")
    with Carousel(direction="down", show_dots=True, controls_position="outside", loop=True, css_class="w-full"):
        Div(css_class="bg-blue-500 rounded-lg", style={"height": "160px"})
        Div(css_class="bg-emerald-500 rounded-lg", style={"height": "160px"})
        Div(css_class="bg-violet-500 rounded-lg", style={"height": "160px"})

    H3("Vertical reel (auto advance)")
    with Carousel(direction="down", auto_advance=2000, show_controls=False, loop=True, css_class="w-full"):
        Div(css_class="bg-blue-500 rounded-lg", style={"height": "160px"})
        Div(css_class="bg-emerald-500 rounded-lg", style={"height": "160px"})
        Div(css_class="bg-violet-500 rounded-lg", style={"height": "160px"})
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-6 w-full",
    "type": "Column",
    "children": [
      {"content": "Vertical with controls", "type": "H3"},
      {
        "cssClass": "w-full",
        "type": "Carousel",
        "visible": 1,
        "gap": 16,
        "direction": "down",
        "loop": true,
        "autoAdvance": 0,
        "continuous": false,
        "speed": 2,
        "effect": "slide",
        "dimInactive": false,
        "showControls": true,
        "controlsPosition": "outside",
        "showDots": true,
        "pauseOnHover": true,
        "align": "start",
        "slidesToScroll": 1,
        "drag": true,
        "children": [
          {
            "cssClass": "bg-blue-500 rounded-lg",
            "type": "Div",
            "style": {"height": "160px"}
          },
          {
            "cssClass": "bg-emerald-500 rounded-lg",
            "type": "Div",
            "style": {"height": "160px"}
          },
          {
            "cssClass": "bg-violet-500 rounded-lg",
            "type": "Div",
            "style": {"height": "160px"}
          }
        ]
      },
      {"content": "Vertical reel (auto advance)", "type": "H3"},
      {
        "cssClass": "w-full",
        "type": "Carousel",
        "visible": 1,
        "gap": 16,
        "direction": "down",
        "loop": true,
        "autoAdvance": 2000,
        "continuous": false,
        "speed": 2,
        "effect": "slide",
        "dimInactive": false,
        "showControls": false,
        "controlsPosition": "outside",
        "showDots": false,
        "pauseOnHover": true,
        "align": "start",
        "slidesToScroll": 1,
        "drag": true,
        "children": [
          {
            "cssClass": "bg-blue-500 rounded-lg",
            "type": "Div",
            "style": {"height": "160px"}
          },
          {
            "cssClass": "bg-emerald-500 rounded-lg",
            "type": "Div",
            "style": {"height": "160px"}
          },
          {
            "cssClass": "bg-violet-500 rounded-lg",
            "type": "Div",
            "style": {"height": "160px"}
          }
        ]
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

Set `direction="right"` to scroll in the opposite horizontal direction (content moves right to left).

## Marquee

Set `continuous=True` for smooth, never-ending scroll. Unlike auto-advance which pauses between slides, continuous mode scrolls at a constant velocity — like a news ticker or stock tape. Control the speed from 1 (gentle drift) to 10 (racing).

Children are automatically duplicated behind the scenes so the loop is seamless regardless of how many items you provide.

Stack multiple marquees at different speeds for a layered, dynamic feel:

<ComponentPreview json={{"view":{"cssClass":"gap-4 w-full","type":"Column","children":[{"cssClass":"w-full","type":"Carousel","gap":16,"direction":"left","loop":true,"autoAdvance":0,"continuous":true,"speed":1,"effect":"slide","dimInactive":false,"showControls":false,"controlsPosition":"outside","showDots":false,"pauseOnHover":true,"align":"start","slidesToScroll":1,"drag":true,"children":[{"cssClass":"mx-2","type":"Badge","label":"Python","variant":"default"},{"cssClass":"mx-2","type":"Badge","label":"React","variant":"default"},{"cssClass":"mx-2","type":"Badge","label":"TypeScript","variant":"default"},{"cssClass":"mx-2","type":"Badge","label":"Tailwind","variant":"default"},{"cssClass":"mx-2","type":"Badge","label":"Embla","variant":"success"},{"cssClass":"mx-2","type":"Badge","label":"Prefab","variant":"success"}],"visible":null},{"cssClass":"w-full","type":"Carousel","gap":16,"direction":"left","loop":true,"autoAdvance":0,"continuous":true,"speed":3,"effect":"slide","dimInactive":false,"showControls":false,"controlsPosition":"outside","showDots":false,"pauseOnHover":true,"align":"start","slidesToScroll":1,"drag":true,"children":[{"cssClass":"mx-2","type":"Badge","label":"Charts","variant":"default"},{"cssClass":"mx-2","type":"Badge","label":"Tables","variant":"default"},{"cssClass":"mx-2","type":"Badge","label":"Forms","variant":"default"},{"cssClass":"mx-2","type":"Badge","label":"Buttons","variant":"default"},{"cssClass":"mx-2","type":"Badge","label":"Cards","variant":"default"},{"cssClass":"mx-2","type":"Badge","label":"Dialogs","variant":"default"},{"cssClass":"mx-2","type":"Badge","label":"Mermaid","variant":"success"},{"cssClass":"mx-2","type":"Badge","label":"Carousel","variant":"success"}],"visible":null},{"cssClass":"w-full","type":"Carousel","gap":16,"direction":"left","loop":true,"autoAdvance":0,"continuous":true,"speed":6,"effect":"slide","dimInactive":false,"showControls":false,"controlsPosition":"outside","showDots":false,"pauseOnHover":true,"align":"start","slidesToScroll":1,"drag":true,"children":[{"cssClass":"mx-2","type":"Badge","label":"Alerts","variant":"default"},{"cssClass":"mx-2","type":"Badge","label":"Reports","variant":"default"},{"cssClass":"mx-2","type":"Badge","label":"Events","variant":"default"},{"cssClass":"mx-2","type":"Badge","label":"Tasks","variant":"default"},{"cssClass":"mx-2","type":"Badge","label":"Metrics","variant":"default"},{"cssClass":"mx-2","type":"Badge","label":"Logs","variant":"default"},{"cssClass":"mx-2","type":"Badge","label":"Realtime","variant":"success"},{"cssClass":"mx-2","type":"Badge","label":"Streaming","variant":"success"}],"visible":null}]}}} playground=" ">
<CodeGroup>
```python icon="python"
from prefab_ui.components import Carousel, Column, Badge

with Column(gap=4, css_class="w-full"):
    with Carousel(continuous=True, speed=1, show_controls=False, css_class="w-full"):
        Badge("Python", css_class="mx-2")
        Badge("React", css_class="mx-2")
        Badge("TypeScript", css_class="mx-2")
        Badge("Tailwind", css_class="mx-2")
        Badge("Embla", variant="success", css_class="mx-2")
        Badge("Prefab", variant="success", css_class="mx-2")

    with Carousel(continuous=True, speed=3, show_controls=False, css_class="w-full"):
        Badge("Charts", css_class="mx-2")
        Badge("Tables", css_class="mx-2")
        Badge("Forms", css_class="mx-2")
        Badge("Buttons", css_class="mx-2")
        Badge("Cards", css_class="mx-2")
        Badge("Dialogs", css_class="mx-2")
        Badge("Mermaid", variant="success", css_class="mx-2")
        Badge("Carousel", variant="success", css_class="mx-2")

    with Carousel(continuous=True, speed=6, show_controls=False, css_class="w-full"):
        Badge("Alerts", css_class="mx-2")
        Badge("Reports", css_class="mx-2")
        Badge("Events", css_class="mx-2")
        Badge("Tasks", css_class="mx-2")
        Badge("Metrics", css_class="mx-2")
        Badge("Logs", css_class="mx-2")
        Badge("Realtime", variant="success", css_class="mx-2")
        Badge("Streaming", variant="success", css_class="mx-2")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-4 w-full",
    "type": "Column",
    "children": [
      {
        "cssClass": "w-full",
        "type": "Carousel",
        "gap": 16,
        "direction": "left",
        "loop": true,
        "autoAdvance": 0,
        "continuous": true,
        "speed": 1,
        "effect": "slide",
        "dimInactive": false,
        "showControls": false,
        "controlsPosition": "outside",
        "showDots": false,
        "pauseOnHover": true,
        "align": "start",
        "slidesToScroll": 1,
        "drag": true,
        "children": [
          {"cssClass": "mx-2", "type": "Badge", "label": "Python", "variant": "default"},
          {"cssClass": "mx-2", "type": "Badge", "label": "React", "variant": "default"},
          {
            "cssClass": "mx-2",
            "type": "Badge",
            "label": "TypeScript",
            "variant": "default"
          },
          {"cssClass": "mx-2", "type": "Badge", "label": "Tailwind", "variant": "default"},
          {"cssClass": "mx-2", "type": "Badge", "label": "Embla", "variant": "success"},
          {"cssClass": "mx-2", "type": "Badge", "label": "Prefab", "variant": "success"}
        ],
        "visible": null
      },
      {
        "cssClass": "w-full",
        "type": "Carousel",
        "gap": 16,
        "direction": "left",
        "loop": true,
        "autoAdvance": 0,
        "continuous": true,
        "speed": 3,
        "effect": "slide",
        "dimInactive": false,
        "showControls": false,
        "controlsPosition": "outside",
        "showDots": false,
        "pauseOnHover": true,
        "align": "start",
        "slidesToScroll": 1,
        "drag": true,
        "children": [
          {"cssClass": "mx-2", "type": "Badge", "label": "Charts", "variant": "default"},
          {"cssClass": "mx-2", "type": "Badge", "label": "Tables", "variant": "default"},
          {"cssClass": "mx-2", "type": "Badge", "label": "Forms", "variant": "default"},
          {"cssClass": "mx-2", "type": "Badge", "label": "Buttons", "variant": "default"},
          {"cssClass": "mx-2", "type": "Badge", "label": "Cards", "variant": "default"},
          {"cssClass": "mx-2", "type": "Badge", "label": "Dialogs", "variant": "default"},
          {"cssClass": "mx-2", "type": "Badge", "label": "Mermaid", "variant": "success"},
          {"cssClass": "mx-2", "type": "Badge", "label": "Carousel", "variant": "success"}
        ],
        "visible": null
      },
      {
        "cssClass": "w-full",
        "type": "Carousel",
        "gap": 16,
        "direction": "left",
        "loop": true,
        "autoAdvance": 0,
        "continuous": true,
        "speed": 6,
        "effect": "slide",
        "dimInactive": false,
        "showControls": false,
        "controlsPosition": "outside",
        "showDots": false,
        "pauseOnHover": true,
        "align": "start",
        "slidesToScroll": 1,
        "drag": true,
        "children": [
          {"cssClass": "mx-2", "type": "Badge", "label": "Alerts", "variant": "default"},
          {"cssClass": "mx-2", "type": "Badge", "label": "Reports", "variant": "default"},
          {"cssClass": "mx-2", "type": "Badge", "label": "Events", "variant": "default"},
          {"cssClass": "mx-2", "type": "Badge", "label": "Tasks", "variant": "default"},
          {"cssClass": "mx-2", "type": "Badge", "label": "Metrics", "variant": "default"},
          {"cssClass": "mx-2", "type": "Badge", "label": "Logs", "variant": "default"},
          {"cssClass": "mx-2", "type": "Badge", "label": "Realtime", "variant": "success"},
          {
            "cssClass": "mx-2",
            "type": "Badge",
            "label": "Streaming",
            "variant": "success"
          }
        ],
        "visible": null
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

### Sized Marquee Slides

Combine `continuous` with `visible` to control slide sizing within the marquee. Without `visible`, each item uses its natural width (badges wrap tightly). With `visible=4`, each item is sized to 25% of the viewport:

<ComponentPreview json={{"view":{"cssClass":"w-full","type":"Carousel","visible":4.0,"gap":12,"direction":"left","loop":true,"autoAdvance":0,"continuous":true,"speed":3,"effect":"slide","dimInactive":false,"showControls":false,"controlsPosition":"outside","showDots":false,"pauseOnHover":true,"align":"start","slidesToScroll":1,"drag":true,"children":[{"cssClass":"bg-blue-500 rounded-lg","type":"Div","style":{"height":"80px"}},{"cssClass":"bg-emerald-500 rounded-lg","type":"Div","style":{"height":"80px"}},{"cssClass":"bg-violet-500 rounded-lg","type":"Div","style":{"height":"80px"}},{"cssClass":"bg-amber-500 rounded-lg","type":"Div","style":{"height":"80px"}},{"cssClass":"bg-purple-500 rounded-lg","type":"Div","style":{"height":"80px"}},{"cssClass":"bg-blue-500 rounded-lg","type":"Div","style":{"height":"80px"}}]}}} playground=" ">
<CodeGroup>
```python icon="python"
from prefab_ui.components import Carousel, Div

with Carousel(continuous=True, speed=3, show_controls=False, visible=4, gap=12, css_class="w-full"):
    Div(css_class="bg-blue-500 rounded-lg", style={"height": "80px"})
    Div(css_class="bg-emerald-500 rounded-lg", style={"height": "80px"})
    Div(css_class="bg-violet-500 rounded-lg", style={"height": "80px"})
    Div(css_class="bg-amber-500 rounded-lg", style={"height": "80px"})
    Div(css_class="bg-purple-500 rounded-lg", style={"height": "80px"})
    Div(css_class="bg-blue-500 rounded-lg", style={"height": "80px"})
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "w-full",
    "type": "Carousel",
    "visible": 4.0,
    "gap": 12,
    "direction": "left",
    "loop": true,
    "autoAdvance": 0,
    "continuous": true,
    "speed": 3,
    "effect": "slide",
    "dimInactive": false,
    "showControls": false,
    "controlsPosition": "outside",
    "showDots": false,
    "pauseOnHover": true,
    "align": "start",
    "slidesToScroll": 1,
    "drag": true,
    "children": [
      {
        "cssClass": "bg-blue-500 rounded-lg",
        "type": "Div",
        "style": {"height": "80px"}
      },
      {
        "cssClass": "bg-emerald-500 rounded-lg",
        "type": "Div",
        "style": {"height": "80px"}
      },
      {
        "cssClass": "bg-violet-500 rounded-lg",
        "type": "Div",
        "style": {"height": "80px"}
      },
      {
        "cssClass": "bg-amber-500 rounded-lg",
        "type": "Div",
        "style": {"height": "80px"}
      },
      {
        "cssClass": "bg-purple-500 rounded-lg",
        "type": "Div",
        "style": {"height": "80px"}
      },
      {
        "cssClass": "bg-blue-500 rounded-lg",
        "type": "Div",
        "style": {"height": "80px"}
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

## API Reference

<ParamField body="visible" type="float | None" default="1">
  How many slides to show at once. Whole numbers (`3`) show that many full slides. Decimals (`1.3`) show partial slides at the edges — 1.3 means one full slide plus 30% of the next. `None` uses each slide's natural width (default for marquee when `visible` is omitted).
</ParamField>

<ParamField body="gap" type="int" default="16">
  Pixels between slides.
</ParamField>

<ParamField body="height" type="int | None" default="None">
  Fixed height in pixels. Vertical carousels auto-detect from the first slide.
</ParamField>

<ParamField body="direction" type="str" default="left">
  Scroll direction: `"left"` (horizontal, default), `"right"` (horizontal, reversed), `"down"` (vertical), or `"up"` (vertical, reversed). For auto-advance and marquee, this controls which way automatic motion goes. For manual navigation, users can scroll either direction regardless.
</ParamField>

<ParamField body="loop" type="bool" default="True">
  Seamless infinite looping. When disabled, the carousel stops at the first and last slides.
</ParamField>

<ParamField body="auto_advance" type="int" default="0">
  Milliseconds between auto-advances. `0` disables auto-advance. The carousel pauses on hover by default.
</ParamField>

<ParamField body="continuous" type="bool" default="False">
  Smooth continuous scroll at constant velocity (marquee mode). Children are auto-duplicated for seamless looping. When omitted, `visible` defaults to `None` (natural sizing).
</ParamField>

<ParamField body="speed" type="int" default="2">
  Scroll speed for continuous mode, from 1 (gentle) to 10 (fast).
</ParamField>

<ParamField body="effect" type="str" default="slide">
  Transition effect: `"slide"` (horizontal/vertical movement) or `"fade"` (crossfade in place).
</ParamField>

<ParamField body="dim_inactive" type="bool" default="False">
  Reduce opacity on non-active slides. Most effective with peek or multiple visible slides.
</ParamField>

<ParamField body="show_controls" type="bool" default="True">
  Show previous/next navigation arrows.
</ParamField>

<ParamField body="controls_position" type="str" default="overlay">
  Arrow placement: `"overlay"` positions arrows on top of the slides, `"outside"` places them flanking the viewport.
</ParamField>

<ParamField body="show_dots" type="bool" default="False">
  Show pagination dots indicating current position and total slides.
</ParamField>

<ParamField body="pause_on_hover" type="bool" default="True">
  Pause auto-advance or continuous scroll when the user hovers over the carousel.
</ParamField>

<ParamField body="align" type="str" default="start">
  Slide alignment within the viewport: `"start"`, `"center"`, or `"end"`. Most noticeable with peek — `"center"` shows equal peek on both sides.
</ParamField>

<ParamField body="slides_to_scroll" type="int" default="1">
  How many slides to advance per navigation step.
</ParamField>

<ParamField body="drag" type="bool" default="True">
  Allow drag/swipe to navigate.
</ParamField>

<ParamField body="css_class" type="str">
  Additional CSS classes for the carousel container.
</ParamField>
