BACKGROUND
An image carousel is a great way to showcase specific images on your website. This can enhance the overall visual appearance of your website and also improve the general user experience.
In this article, you'll learn how you can prototype a simple image carousel using Cloudinary, Next.js, and Framer-Motion as illustrated in the Codesandbox below.
Prerequisites
Before getting started, ensure that you have the following:
- Node.js. installed.
- Basic understanding of JavaScript/React
- Cloudinary Account
Project Setup
To get started with Next.JS, navigate to the project directory of your choice and run:
1npx create-next-app carousel
The command will set up everything automatically for you. After the installation is complete, follow the instructions on your terminal to start the development server.
Set Up Dependencies
Install the following dependencies in your project:
1npm i cloudinary react-icons framer-motion
The carousel will use the Cloudinary package to interact with the images stored in cloudinary while react icons will be used to display image navigation arrows on the carousel. The framer motion package will be used to animate the fetched images.
As we shall be using cloudinary for retrieval of the carousel images, create a .env.local file in the root of the project directory. This is where we shall store all our environment variables configurations. Content stored in this file are not included in the browser build. This file should always be included in your gitignore
file as it stores sensitive information.
To the file add the following keys :
1CLOUDINARY_CLOUD_NAME=2CLOUDINARY_API_KEY=3CLOUDINARY_API_SECRET=
Their respective values will be acquired from the Cloudinary dashboard.
Cloudinary setup
Once you have created an account on Cloudinary, copy your cloud_name, api_key & api_secret
from the dashboard, and add them as values to the respective keys in the .env.local
file created in the application.
The next step is to create a folder where all of the carousel images will be stored. Click on the Media Library tab, and create a folder named Carousel
. We will programmatically access the contents of the folder.
The last step is to upload the images you want to see on the carousel to the folder. For demo purposes, you can download free stock photos from Pexels.
To interact with the images stored in Cloudinary from the application, create a utils
folder in the root project structure of your application, and add a cloudinary.js
file in it.
This file will be used to store all the snippets that you will use throughout the application to interact with Cloudinary.
Paste the following to the file:
1import cloudinary from 'cloudinary';23cloudinary.config({4 cloud_name: process.env.CLOUDINARY_CLOUD_NAME,5 api_key: process.env.CLOUDINARY_API_KEY,6 api_secret: process.env.CLOUDINARY_API_SECRET,7});8}
I imported the Cloudinary package from the code above and configured the required configuration keys to access all the assets stored in Cloudinary. By using process.env
, one can access values stored in the .env.local
file.
The next step is to create an asynchronous function that will fetch all images from Cloudinary:
1export async function getAllImages() {23 const response = await cloudinary.v2.api.resources({4 type: 'upload',5 prefix: 'Carousel',6 });78 const sliderData = response.resources.map((image, key) => ({9 id: key,10 ...image,11 }));1213 return sliderData;14}
By using cloudinary.v2.api.resources
, one can manage and access all the resources (images) stored in the Carousel
folder. After querying the Images stored in the folder, convert the JSON response received into an array of objects for easy image mapping when it comes to fetching data on the frontend.
The last configuration we need to make, to help the Next.JS application communicate with Cloudinary effectively, is to create a next.config.js
file in the root project structure, and add the following to it:
1module.exports = () => {2 return {3 images: {4 domains: ['res.cloudinary.com'],5 },6 };7};
This will allow us to let Cloudinary optimize images instead of using Next's built-in image optimization.
With all the above setup and configurations, it's time to spin up the server.
Server setup
Next.js supports writing server-side code rendering out of the box. For this to happen, navigate to the page's directory, and create an API
folder. Inside it, create a Cloudinary.JS
file, and paste the following :
1import { getAllImages } from '../../utils/cloudinary';234async function handler(req, res) {5 if (req.method === 'GET') {6 try {78 const sliderData = await getAllImages();910 res.status(200).json(sliderData);1112 } catch (error) {1314 res.status(500).json({ message: 'Getting images failed.' });15 }16 }17}1819export default handler;
From the above, we first import the getAllImages
function we created in the utils folder to be able to access all the images stored in Cloudinary. Then, we create an 'if' statement to define the method GET
and fetch data from the defined endpoint.
Then, create a try & catch
statement where we assign the getAllImages
function to the variable sliderData
to fetch the data or catch all the errors that might occur in the process of fetching the images from Cloudinary. Lastly, we export the function so that it is globally available.
To test out if the endpoint works. visit your browser or postman, and make a GET
request to endpoint http://localhost:3000/api/cloudinary
. This should produce the following response :
Image Slider Component
To be able to consume the Api we created and show all the data to the application users, create a components folder on the root of the application and add an ImageSlider.js
file to it. This will be a normal react component.
Component setup
This component will fetch all the images from the cloudinary and showcase them in an image slider. We shall use the Fetch API
to perform data fetching from the API and reacts useState
to set the images into the page state.
Create a functional component as follows:
1import React, { useState } from 'react';234 let images = [];56 fetch("/api/cloudinary")7 .then((response) => response.json())8 .then((data) => {9 images = data.map((image) => {10 return image.url;11 });12 );1314const ImageSlider = () => {15const [[page, direction], setPage] = useState([0, 0]);16const imageIndex = wrap(0, images.length, page);171819 return (2021 );22};2324export default ImageSlider;
Above, we first declared images as an empty array after which we used the Fetch
API to get all the images from Cloudinary and store them into the images variable.
Each fetched image will be displayed on a separate page hence storing all the pages in the application state. This will enable us to loop through the different images from the API once the application state changes.
To be able to navigate through the different Images, create a function that will shift the pages(image) based on the direction triggered as illustrated below :
1const paginate = (newDirection) => {2 setPage([page + newDirection, newDirection]);3 };
Then, create a variable that will store all the images based on their indexes so that the different image pages can be displayed on the Next.js image component:
1const src = images.length > 0 ? images[imageIndex] : `/amazon.jpg`;
NEXT.JS IMAGE OPTIMIZATION
To optimize how we load, optimize and resize images on various screen sizes, we utilized the image component which resizes all the carousel images on the fly.
We must first import the image component on top of the page to use it:
1import Image from 'next/image';
Create a div in the return statement and add the following code to display the various image pages based on their indexes:
1<Image2 src={src}3 alt="Picture of the author"4 width={600}5 height={600}6 />
Animating The Image Carousel With Framer Motion
Framer motion is a powerful and easy-to-use library that can quickly help us achieve smooth image transition effects. It allows us to combine various animation types and serve as a solid foundation for making your pages even more user-friendly.
Importing the motion component and the other animation components that come with the library is the first step in using it.
In our case, we'll make use of the AnimatePresence
component.
Fontawesome imports will be used to create navigation icons.
1import { motion, AnimatePresence } from "framer-motion";2import { FaAngleRight } from "react-icons/fa";
The next step is to wrap everything inside the return statement with the AnimatePresence component. By changing the different keys within the component it will create an Animated slideshow.
Create a div between the Animate presence component and Add the following to it :
1<AnimatePresence>2<motion.div3 className={styles.img}4 key={page}5 custom={direction}6 initial={{ x: 300, opacity: 0 }}7 animate={{ x: 0, opacity: 1 }}8 exit={{ opacity: 0 }}9 whileHover={{ scale: 1.1 }}10 whileTap={{ scale: 0.9 }}11 transition={{12 x: { type: "spring", stiffness: 300, damping: 300 },13 opacity: { duration: 1 }14 }}15>16 </motion.div>17</AnimatePresence>
Move the image component between the motion div
for the transitions and animations applied to take effect on the optimized images.
Above we utilized transitions, whileHovers, whileTap, and the animate properties from framer motion to give the image carousel a smooth transition
We need to add back and forward navigation buttons below the AnimatePresence component to complete the component. This will be accomplished in the following ways:
1<motion.div2 className={styles.next}3 onClick={() => paginate(1)}4 whileHover={{ scale: 1.2, transition: { duration: 0.5 } }}5 whileTap={{ scale: 0.9 }}6>7 <FaAngleRight />8</motion.div>
1<motion.div2 className={styles.prev}3 onClick={() => paginate(-1)}4 whileHover={{ scale: 1.2, transition: { duration: 0.5 } }}5 whileTap={{ scale: 0.9 }}6>7 <FaAngleRight />8</motion.div>
By using the motion property on the button divs
above we were also able to animate the navigation buttons when we hover and tap on them. We used Fontawesome to create the navigation signs inside the buttons.
Image Display
To display the ImageSlide.js
component we just created, navigate to the pages folder and on the default index.js
file, create a Homepage
function and embed the image slider component as shown below.
1function HomePage({ sliderData }) {2 return (3 <Layout>4 <ImageSlider/>5 </Layout>6 );7}
Conclusion
You have successfully built an image carousel leveraging on Framer Motion, Next's massive capabilities such as out-of-the-box API & image component while using cloudinary as your image storage and manipulation tool.
Feel free to improve the application and make it better.
For reference visit: