DEV Community

4aLifeTime
4aLifeTime

Posted on

¿Cómo crear un Carrusel con Next y Chakra UI?

En este post, vamos a desarrollar un Carrusel utilizando la librería Embla Carousel, el framework Next.js y la librería Chakra UI - esta última, al igual que Next.js, desarrollada por Vercel y la comunidad Open Source.

A lo largo del post, aprenderemos:

  • Por qué elegir Embla Carousel
  • Cómo integrar Embla Carousel a tu proyecto en Next.js y Chakra UI
  • Cómo agregar paginación a tu Carousel

Si querés ir directamente al repositorio en GitHub puedes hacerlo desde aquí


¿Qué es Embla Carousel?

Embla Carousel es una librería agnóstica que, como su nombre lo indica, facilita la construcción de carruseles. Su uso garantiza fluidez y precisión tanto en el movimiento como deslizamiento de los elementos (slides) que componen al carrusel. Es una librería dependency-free y liviana, por lo que su instalación es rápida y posee una baja dependencia de otras librerías para su funcionamiento.

De muy fácil integración a tu proyecto, con una API muy bien documentada y una extensa lista de plugins que permiten potenciar las funciones de tu componente carrusel.

Por último, Embla Carousel funciona en todos los navegadores modernos, incluido IE11.


Configurar nuestro proyecto

Crea un proyecto nuevo utilizando el comando create-next-app:

npx create-next-app my-awesome-embla-carousel
Enter fullscreen mode Exit fullscreen mode

Una vez creado el proyecto y dentro del mismo, vamos a continuar instalando las dependencias necesarias para integrar Chakra UI. Según la documentación oficial:

npm i @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^6
# or
yarn add @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^6
Enter fullscreen mode Exit fullscreen mode

Por último, pero no menos importante, vamos a agregar a nuestro proyecto la versión de la librería Embla Carousel para React:

npm install embla-carousel-react --save
Enter fullscreen mode Exit fullscreen mode

Hasta el momento, tu archivo package.json debería verse de la siguiente manera:

Listado de dependencias en el archivo package.json

Recuerda que las versiones de las dependencias pueden variar. Al momento de escribir este post, la versión de la librería Embla Carousel React es la 6.2.0


Estructura básica del componente Carousel

Para su integración con React, Embla Carousel provee el hook useEmblaCarousel. El mismo devuelve dos parámetros, la referencia al carrusel que luego será utilizada en la composición visual de nuestro componente y la API que nos dará acceso a todos los métodos disponibles.

import useEmblaCarousel from 'embla-carousel-react'

const [emblaRef, emblaApi] = useEmblaCarousel()
Enter fullscreen mode Exit fullscreen mode

A su vez, useEmblaCarousel permite la asignación de opciones globales a nuestro carrusel. A modo de ejemplo:

  const [emblaRef, embla] = useEmblaCarousel({

    // alinea el primer slide al principio del viewport,
    // caso contrario, por defecto, lo hará en el medio
    align: "start",

    // si el carrusel llegá al final retorna 
    // automáticamente al primer slide
    loop: true,

    // determina si el usuario puede desplazar los slides
    // a través del mouse u otra interacción. Por defecto: true
    draggable: false,

    // determina la velocidad de desplazamiento entre slides.
    speed: 15,

    // ... más opciones globales
  });
Enter fullscreen mode Exit fullscreen mode
  • la asignación de opciones globales debe realizarse por única vez y hacerse antes de inicializar el carrusel. Caso contrario, re asignar opciones globales puede producir efectos inesperados en el comportamiento del componente carrusel.

Para una lista detallada de las opciones globales posibles, consultar aquí.

Por otro lado, la composición visual de nuestro carrusel va a requerir de una estructura básica de tres elementos - o sub componentes:

Viewport

  • El hook nos da una referencia para asociar al elemento envolvente - padre -, necesario para manipular el excedente o desbordamiento con la propiedad overflow:hidden

Container

  • Un contenedor que encerrará todos los slides del carrusel bajo la propiedad flex-row

Slides

  • Tendrá un listado con cada slide de nuestro carrusel

Comencemos a programar

Hasta ahora:

  • Aprendimos qué es Embla Carousel
  • Instalamos un proyecto Next.js
  • Limpiamos la estructura de nuestro proyecto
  • Agregamos las dependencias necesarias de Embla Carousel y Chakra UI

¡Es hora de empezar a trabajar con código! Vamos a construir un carrusel con repositorios de proyectos bajo distintas tecnologías y programadores. La información para completar cada slide - imagen, desarrollador, titulo, indicadores, descripción, ect - puede ser consumida de forma local o directamente desde una API. En nuestro caso, usaremos un archivo local repositories.js al proyecto que provee un arreglo de objetos con toda la información necesaria. Para la navegación entre los slides usaremos de ejemplo una paginación de puntos (dot's type pagination).

Prevista del proyecto carrusel terminado

Nuestro archivo index.jsx debería verse de la siguiente manera:

import { ChakraProvider } from '@chakra-ui/react'
import useEmblaCarousel from 'embla-carousel-react'
import { useEffect, useCallback, useState } from 'react'
import { Container, Flex, Heading, Button, Box } from '@chakra-ui/react'
import SlideImage from '../components/SlideImage'
import SlideDetails from '../components/SlideDetails'
import repositories from '../../repositories'

const EmblaCarousel = () => {
  const [emblaRef, emblaApi] = useEmblaCarousel({ loop: false })
  const [scrollSnaps, setScrollSnaps] = useState([]);
  const [selectedIndex, setSelectedIndex] = useState(0);

  /* 
   * función que a través de la API de Embla Carousel
   * y el método scrollTo permite navegar al índice
   * correspondiente al "dot" de la navegación
   */
  const scrollTo = useCallback(
    (index) => emblaApi && emblaApi.scrollTo(index),
    [emblaApi]
  );

  /*
   * función que actualiza el estado del índice
   * correspondiente al slide actual  
   */
  const onSelect = useCallback(() => {
    if (!emblaApi) return;
    setSelectedIndex(emblaApi.selectedScrollSnap);
  }, [emblaApi, setSelectedIndex]);

  /*
   * por cada re-renderizado del componente nos aseguramos que
   * la librería Embla esté "montada" correctamente
   */
  useEffect(() => {
    if (!emblaApi) return;
    onSelect();
    setScrollSnaps(emblaApi.scrollSnapList);
    emblaApi.on("select", onSelect);
  }, [emblaApi, setScrollSnaps, onSelect]);

  return (
    {/* código de renderizado detallado abajo */}
  )
}

export default EmblaCarousel
Enter fullscreen mode Exit fullscreen mode

Seguimos sumando código a nuestro archivo index.jsx, ahora el encargado de renderiza el elemento Carrusel:

return (
    <ChakraProvider>
      <Box bg="#030c1b" minHeight="100vh">

        <Container maxW="100%" py={10} >
          <Heading textAlign="center" color="white">
            My awesome Embla Carousel using + NextJS + Chakra
          </Heading>
        </Container>

        {/* Viewport */}
        <Box overflow="hidden" maxW="100%" p={0} ref={emblaRef} >
          {/* Container */}
          <Flex h='auto' py={[0, 5, 5]}>
            {/* Slides */}
            {repositories.map(repo => {
              return (
                <Flex key={repo.id} direction={{ base: 'column', md: 'row' }} justifyContent="center" position="relative" flex="0 0 100%">
                  <SlideImage imageSrc={repo.imgSrc} />
                  <SlideDetails item={repo} />
                </Flex>
              )
            })}
          </Flex>
        </Box>
      </Box>
    </ChakraProvider>
)
Enter fullscreen mode Exit fullscreen mode

Considere que los componentes SlideImage y SlideDetails tienen el objetivo de agregarle sentido en términos tanto de diseño como de contenido al carrrusel. Si lo desean podrán descargarlos directamente desde acá, sino, podrán crear su propio contenido y diseño.

Las imágenes utilizadas, pueden descargarse también del repositorio desde aquí. Las mismas están ubicadas en la carpeta public/images de Next.js, destinada para servir archivos estáticos.

Hasta ahora, le hemos dado estilo a nuestro componente carrusel de repositorios, donde cada slide posee una imagen a la izquierda y detalles del repositorio a la derecha. Además, el componente ocupará el 100% de la viewport por lo que se mostrará de a un slide a la vez.

Por último, nos queda agregar el sistema de paginación de puntos. El mismo nos da una idea de la cantidad de elementos - slides - que posee el carrusel y a la vez provee una herramienta práctica para desplazarse entre cada slide.

Agregamos el siguiente código al final de nuestro archivo index.jsx, dentro del provedor de contexto de Chakra UI(ChakraProvider):

return (
    <ChakraProvider>

        {/* código correspondiente al elemento carrusel */}

        <Container maxW="container.xl" py={10}>
        <Flex justifyContent="center" alignItems="center" mt={5}>
            {scrollSnaps.map((_, idx) => (
            <Button w={2} h={2} mx={1} size="3" bg={idx === selectedIndex ? "yellow.500" : "gray.300"} key={idx} 
            onClick={() => scrollTo(idx)}/>
            ))}
        </Flex>
        </Container>
    </ChakraProvider>
)
Enter fullscreen mode Exit fullscreen mode

Terminamos!! Recordá que cualquier duda o comentario siempre serán bienvenidos!

Podés descargarte el repositorio del proyecto completo desde aquí.


Conclusiones

Hemos aprendido a crear fácilmente un carrusel con la ayuda de la librería Embla Carousel e integrarlo a nuestro proyecto de Next.js y Chakra UI.

Embla Carousel es muy simple y te permite crear elementos con tu propio estilo según tus necesidades.

Hasta la próxima!!!

Links de interes

Embla Carousel
React Embla Carousel
Embla API
Next.js
Chakra UI

Top comments (0)