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
| Prop | Tipo | Padrão | Descrição |
|---|---|---|---|
children | React.ReactNode[] | — | Slides. Cada filho direto vira um item do carrossel. |
interval | number | 3500 | Intervalo de avanço automático em milissegundos. |
className | string | — | Classe 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:
setIntervalchamaapi.scrollNext()a cadaintervalms. O timer é limpo viaclearIntervalao desmontar o componente ou quandoapimuda. - Sincronização dos dots: o evento
selectdo Embla disparasetCurrent(api.selectedScrollSnap())a cada transição de slide. - Dots visuais: o dot ativo tem
w-6 opacity-80; os inativos têmw-2 opacity-25. Todos usambg-currente 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(...)}.