Pular para o conteúdo principal

AutoCarousel — Carrossel com avanço automático

AutoCarousel é um componente genérico de carrossel com avanço automático e dots de navegação clicáveis. Cada filho direto vira um slide. É construído sobre o Carousel do Shadcn UI (Embla Carousel) e vive em packages/ui.

Importação

import { AutoCarousel } from '@kit/ui/auto-carousel';

Props

PropTipoPadrãoDescrição
childrenReact.ReactNode[]Slides. Cada filho direto vira um item do carrossel.
intervalnumber3500Intervalo de avanço automático em milissegundos.
classNamestringClasse aplicada ao wrapper externo. Útil para controle responsivo.

Uso básico

<AutoCarousel>
{ITEMS.map((item) => (
<div key={item.id} className="rounded-lg p-6 bg-white">
{item.title}
</div>
))}
</AutoCarousel>

Controle responsivo

O padrão mais comum é exibir o carrossel no mobile e um grid no desktop:

{/* Mobile: carrossel com avanço a cada 4 segundos */}
<AutoCarousel className="md:hidden" interval={4000}>
{ITEMS.map((item) => <Card key={item.id} {...item} />)}
</AutoCarousel>

{/* Desktop: grid 3 colunas */}
<div className="hidden md:grid md:grid-cols-3 gap-6">
{ITEMS.map((item) => <Card key={item.id} {...item} />)}
</div>

Comportamento interno

  • Autoplay: setInterval chama api.scrollNext() a cada interval ms. O timer é limpo via clearInterval ao desmontar o componente ou quando api muda.
  • Sincronização dos dots: o evento select do Embla dispara setCurrent(api.selectedScrollSnap()) a cada transição de slide.
  • Dots visuais: o dot ativo tem w-6 opacity-80; os inativos têm w-2 opacity-25. Todos usam bg-current e herdam a cor do contexto pai.
  • Loop: configurado com opts={{ loop: true }} — o carrossel volta ao início após o último slide sem animação de rebote.

Localização do arquivo

packages/ui/src/shadcn/auto-carousel.tsx

Exportado em packages/ui/package.json como:

"./auto-carousel": "./src/shadcn/auto-carousel.tsx"
aviso

children deve ser um array. Se você passar um único elemento sem wrapping em array, o carrossel terá apenas um slide e os dots não renderizarão corretamente. Sempre mapeie de um array: {items.map(...)}.