Video thumbnail with a preview on hover in Next.js

Chris Achinga

Video previews have become a standard feature on most media platforms and applications. YouTube provides a perfect example where a user is presented with a video preview when the mouse pointer hovers over the thumbnail.

A thumbnail is an image preview of the actual video, as shown in the image below:

This post discusses creating video thumbnail previews on hover using Cloudinary and NextJS. At the end of this tutorial, we will learn how to use Cloudinary's video functionality in a website to create a preview on the hover feature and add videos to our pages.

Demo and Source Code

We completed this project in a CodeSandbox, and you can fork it to run the code.

GitHub link here.


  • A Cloudinary account - create a free account here
  • Knowledge of React.js and NextJS
  • Node.js version 12+

Getting Started

To create a NextJS application, run the terminal command below.

1npx creat-next-app thumbnail-preview && cd thumbnail-preview

To confirm that NextJS installed successfully, start a local development server in the project’s directory using the command:

1npm run dev

The local development server for NextJS runs on port 3000, i.e. localhost:3000 on a web browser.

We will use Bootstrap CSS to style the app’s pages, as it provides ready to use classes CSS classes. To install Bootstrap, we run the command:

1npm install bootstrap

After installation, we import Bootstrap into our project by adding the following line at the top of pages/_app.js.

1import 'bootstrap/dist/css/bootstrap.css'

Uploading media to Cloudinary

Navigate to the Media Library after signing in to a Cloudinary account, to upload videos.

The quickest way to upload videos to Cloudinary is by dragging and dropping the file to the Media Library Dashboard. The other way is by using the upload button on the top right of the webpage.

After the video is uploaded, use the link icon on the top right of the video card to copy its URL.

Creating the video player

In the Home component of pages/index.js, we create an array with the video URLs and their titles.

1const Home = () => {
2 const media_urls = [
3 {
4 id: 1,
5 title: 'Video One',
6 video_url:
7 '',
8 },
9 {
10 id: 2,
11 title: 'Video Two',
12 video_url:
13 '',
14 },
15 {
16 id: 3,
17 title: 'Video Three',
18 video_url:
19 '',
20 },
21 ]
22 return (
23 <>
24 <h1 className='text-center'>Cloudinary Video Show</h1>
25 <div className='container'>
26 <div className='row'>
27 <div className='container'>
28 </div>
29 </div>
30 </div>
31 </>
32 )
33 }
34 export default Home

We will render each video using the native HTML video element.

1<video width='320' height='240' controls>
2 <source src={media.video_url} type='video/mp4' />

In the Home component, we loop through the array with video info and render each video.

1const Home = () => {
2 const media_urls = [
3 // media URLs here
4 ]
5 return (
6 <>
7 <h1 className='text-center'>Cloudinary Video Show</h1>
8 <div className='container'>
9 <div className='row'>
10 <div className='container'>
11 { => (
12 <div key={} className='col-lg-4 col-md-4'>
13 <h1>{media.title}</h1>
14 <video width='320' height='240' controls>
15 <source src={media.video_url} type='video/mp4' />
16 </video>
17 </div>
18 ))}
19 </div>
20 </div>
21 </div>
22 </>
23 )
24 }
25 export default Home

Creating event handlers

The next step, we will create event handlers to trigger a preview on hover over the thumbnails. We will utilise the mouse events.

We will utilize onMouseEnter and onMouseLeave events. From the react documentation, the events are triggered when a pointer is over the targeted element(onMouseEnter) and immediately the pointer leaves the targeted element(onMouseLeave).

In our home page component, we will create two functions to handle the two events; handleMouseEnter() and handleMouseLeave().

1// handle mouse enter
2const handleMouseEnter = (e) => {}
3// handle mouse leave
4const handleMouseLeave = (e) => {}

To start the video preview on hover, we modify the handleMouseEnter() to:

1const handleMouseEnter = (e) => {
2 const vid =
3 vid.muted = true

The above function, grabs the <video></video> which we use one of the element’s built in events. vid.muted is set to true, that means sound is disabled, and starts playing the video.

To stop the video playback and return it to its original state, we modify the handleMouseLeave() function to:

1const handleMouseLeave = (e) => {
2 const vid =
3 vid.muted = false
4 vid.currentTime = 0
5 vid.pause()
6 }

Triggering the Events

We need to trigger the two mouse events: onMouseEnter and onMouseLeave to enable the preview. Modify the video element to:

2 width='320'
3 height='240'
4 controls
5 onMouseEnter={handleMouseEnter}
6 onMouseLeave={handleMouseLeave}
7 >
8 <source src={media.video_url} type='video/mp4' />
9 </video>

The complete code in the Home component is shown below:


We went through uploading video files to our Cloudinary account, rendered the videos on a web page, and finally implemented an autoplay preview when hovering on the video.

Useful resources:

Chris Achinga

Technical Writer