Carousel Carrossel
Introdução
Uma apresentação de slides que pagina por um conjunto de slides usando CSS
scroll-snap real e nativo — não cálculos de transform. Suporta paginação por
grupo (slidesPerPage), loop, reprodução automática, rolagem com arraste do
mouse, navegação por teclado e orientação vertical.
Uso
Carrossel básico
import { Carousel } from "../components/ui";
export default function Page() {
return (
<Carousel
slides={[
<div>Slide 1</div>,
<div>Slide 2</div>,
<div>Slide 3</div>,
]}
/>
);
}
Múltiplos slides por página, com loop
<Carousel
slides={slides}
slidesPerPage={3}
spacing="16px"
loop
colorPalette="purple"
/>
Reprodução automática com pausa ao passar o cursor
<Carousel
slides={slides}
autoplay={{ delay: 2500 }}
pauseOnHover
loop
showAutoplayTrigger
/>
Orientação vertical
<div class={css({ height: "72" })}>
<Carousel slides={slides} orientation="vertical" class={css({ height: "full" })} />
</div>
Controles sobrepostos (inline)
<Carousel slides={slides} inline loop />
Construtor de Páginas CMS
Este componente está disponível como um bloco carousel no Construtor de Páginas (content/pages/*.json). Os slides são registros simples { image, caption, href }, não blocos de componentes aninhados:
{
"type": "carousel",
"slides": [
{ "image": "/hero-1.jpg", "caption": "Slide 1" },
{ "image": "/hero-2.jpg", "caption": "Slide 2" }
],
"loop": true,
"autoplayDelay": 3000
}
Propriedades
Carousel
O componente de conveniência orientado a dados: passe slides e ele compõe
ItemGroup/Item mais um Control padrão (gatilhos de anterior/próximo e
pontos indicadores) para você. Para composição manual completa, use
Carousel.Root e as partes exportadas diretamente (ver
Composição manual).
| Prop | Type | Description | Default |
|---|---|---|---|
slides | JSX.Element[] | O conteúdo dos slides. slideCount é derivado de seu comprimento. | - |
interactive | boolean | Força a hidratação como uma ilha. | true |
page | number | Se o carrossel está em uma determinada página (controlado). | - |
defaultPage | number | Página inicial (não controlado). | 0 |
slidesPerPage | number | Número de slides visíveis de uma vez. | 1 |
| slidesPerMove | `number \ | "auto"` | Slides avançados por passo de página. "auto" usa slidesPerPage. | "auto" |
| orientation | `"horizontal" \ | "vertical"` | Eixo de rolagem. | "horizontal" |
| loop | boolean | Volta ao início na primeira/última página. | false |
| spacing | string | Espaço entre slides (qualquer comprimento CSS). | "0px" |
| padding | string | Padding de rolagem extra em cada extremidade (qualquer comprimento CSS). | - |
| autoSize | boolean | Permite que os slides se dimensionem sozinhos em vez de se dividirem igualmente por slidesPerPage. | false |
| allowMouseDrag | boolean | Habilita rolagem por clicar-e-arrastar com o mouse (a rolagem por toque/trackpad sempre funciona nativamente). | false |
| autoplay | `boolean \ | { delay: number }` | Avança as páginas automaticamente. Sempre volta ao início ao final, independentemente de loop. | false |
| pauseOnHover | boolean | Pausa a reprodução automática enquanto o ponteiro está sobre o carrossel. | false |
| snapType | `"proximity" \ | "mandatory"` | Rigor do scroll-snap CSS. | "mandatory" |
| disabled | boolean | Desabilita todos os gatilhos/indicadores e o arraste. | false |
| showControls | boolean | Renderiza PrevTrigger/NextTrigger no Control padrão. | true |
| showIndicators | boolean | Renderiza um IndicatorGroup no Control padrão. | true |
| showAutoplayTrigger | boolean | Renderiza um AutoplayTrigger no Control padrão. | false |
| itemClass | string | Classe personalizada aplicada a cada Item gerado. | - |
| size | `"sm" \ | "md" \ | "lg"` | Tamanho dos gatilhos/indicadores. | "md" |
| colorPalette | `"gray" \ | "blue" \ | "cyan" \ | "green" \ | "orange" \ | "purple" \ | "red" \ | "teal" \ | "indigo" \ | "pink" \ | "yellow" \ | "success" \ | "error" \ | "warning"` | Cor de destaque para o indicador ativo/gatilho de autoplay pressionado. | "green" |
| inline | boolean | Sobrepõe o Control sobre o grupo de itens em vez de empilhá-lo abaixo. | false |
| translations | CarouselTranslations | Strings localizadas (aria-labels, texto de progresso). | - |
| onPageChange | (details: { page: number; pageSnapPoint: number }) => void | Chamado quando a página ativa se estabiliza. | - |
| onAutoplayStatusChange | (details: { type: string; isPlaying: boolean; page: number }) => void | Chamado quando a reprodução automática inicia/avança/para. | - |
| onDragStatusChange | (details: { type: string; isDragging: boolean; page: number }) => void | Chamado ao iniciar/mover/finalizar o arraste. | - |
| class | string | Classes CSS personalizadas para o elemento raiz. | - |
| classNames | Record<string, string> | Classes CSS personalizadas por parte (root, itemGroup, item, control, prevTrigger, nextTrigger, indicatorGroup, indicator, autoplayTrigger). | - |
Carousel.Item
| Prop | Type | Description | Default |
|---|---|---|---|
index | number | A posição do slide. Obrigatório. | - |
| snapAlign | `"start" \ | "center" \ | "end"` | Qual borda do slide se ajusta à visão. | "start" |
Carousel.Indicator
| Prop | Type | Description | Default |
|---|---|---|---|
index | number | A página para a qual salta. Obrigatório. | - |
readOnly | boolean | Renderiza o ponto sem um manipulador de clique. | false |
Notas de arquitetura
- Rolagem nativa, não transforms.
ItemGroupé um contêiner realoverflow: autode grid/flex comscroll-snap-type; a paginação chamascrollTo(...)sobre ele. Isso significa que o deslize por toque, a rolagem por trackpad e a rolagem por teclas de seta no elemento focado funcionam mesmo antes de a hidratação terminar — apenas os cliques de gatilho/indicador e a reprodução automática requerem JavaScript. pageSnapPointsé o índice do item em que cada página começa, calculado com a mesma fórmula estrutural que a máquina@zag-js/carouseldo Ark UI usa (getPageSnapPoints) — determinístico apenas a partir deslideCount/slidesPerPage/slidesPerMove, portanto é idêntico no servidor e antes da hidratação (nenhuma medição de layout é necessária para SSR).- Os filhos não são re-renderizados na hidratação. Assim como nas
demais ilhas deste projeto, a raiz interativa do
Carouselcorrigedata-current,disabled,data-inviewearia-hiddendiretamente no DOM já renderizado (verapplyPageStateemcarousel-primitive.tsx) em vez de regenerar os filhosItem/Indicator— o HonoX rehidrata os filhos de uma ilha a partir de um snapshot HTML serializado, sem invocar novamente o componente que os produziu. - Nunca dependa de um
onClickde JSX para um botão gatilho/ indicador. Pelo mesmo motivo:PrevTrigger/NextTrigger/Indicator/AutoplayTriggersão compostos como filhos, então o hono/jsx/dom nunca reconcilia suas próprias props de evento sintéticas sobre esses nós já montados — umonClickneles silenciosamente nunca dispara. Todo o tratamento de clique é delegado a partir da raiz em um únicouseEffect(target.closest('[data-part="..."]')), espelhandodropdown-primitive.tsx/combobox-primitive.tsx. Esse efeito (e o depauseOnHover) monta exatamente uma vez e lêscrollNext/scrollPrev/isPlaying/etc. por meio de refs em vez de capturá-los diretamente por closure — colocar estado reativo em seu array de dependências reanexaria o listener a cada mudança, e o própriosetIsPlayingdepauseOnHover(disparado porpointerenter, que chega logo antes do clique emparelhado em um gesto de clique real) de outra forma desmontaria o listener de clique no intervalo entre a chegada do mouse e o pressionar do botão. - Simplificações em relação ao Ark UI upstream: o rastreamento de
"em vista" usa a mesma matemática de intervalo de índices que a
renderização SSR (não um
IntersectionObserverreal), e otabindexdeItemGroupé sempre0(não alternado com base em se um slide contém um elemento focável). Ambos são compromissos pragmáticos que cobrem o caso comum deslidesPerPagefixo; RTL (dir) não é suportado, em consonância com o restante desta biblioteca de componentes.