# Inertia carousel (goodtabs UI)

A carousel you throw: drag with momentum, snap to items, native scroll on touch.

## Install

```bash
npx shadcn@latest add https://ui.goodtabs.co/r/inertia-carousel.json
```

Or, with the @goodtabs namespace configured in components.json: `npx shadcn@latest add @goodtabs/inertia-carousel`

## Usage

```tsx
import { InertiaCarousel, InertiaCarouselItem } from "@/components/ui/inertia-carousel"

<InertiaCarousel aria-label="Recent work">
  <InertiaCarouselItem>
    <img src="/work/one.jpg" alt="The new dashboard" />
  </InertiaCarouselItem>
</InertiaCarousel>
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| aria-label | `string` |  | Names the scrolling region on InertiaCarousel. Required. |
| className | `string` |  | On InertiaCarouselItem, set the width. The default is 78vw, then 36rem from md up. |

## When to use

- A short set of visual items that reward browsing, such as case studies or renders
- Full-bleed rows on a marketing page
- When people should feel the weight of what they are moving

## When not to use

- Content people need to compare or read in full: use a grid
- One item at a time on a timer: this never moves by itself
- Inside a parent with a CSS transform, which throws off the measured stops

## Notes for agents

- GSAP installs from npm under GSAP's own licence. No GSAP code ships in this registry
- It is a real scroller at every size. Draggable moves a hidden proxy and writes to scrollLeft, so wheel, trackpad and tabbing into items are native
- Dragging and tweening run only on a fine pointer with motion allowed. Touch and reduced motion get native scroll and CSS snap
- Arrow keys, Home and End work while the region or anything in it has focus. Focusable items are fine

## The maths

- Each stop is min(item left - first left, scrollWidth - clientWidth), so the last items share a stop instead of overscrolling.
- Edge resistance 0.85 means a drag past the end moves the track 15 percent of the distance.
- The progress hairline is scaleX((scrollLeft + clientWidth) / scrollWidth), so it starts at the share in view and never reflows.

Docs: https://ui.goodtabs.co/components/inertia-carousel