Custom JavaScript Video Listing and Selection Interface

While developing the company website at my last job, I was tasked with creating a section on the List With Us page for video testimonials from real estate clients.

Think of YouTube, but with a different design and UI.

This aspect of the website has been a talking point for a few of my past job interviews, so I thought I’d write a post about how I did it.

To the left is the final product.

Essentially, the client videos are stored in an individual container. In this container, you can see the video thumbnail, the clients’ names, if they were buyers or sellers, and what agent they worked with.

It should be noted that clicking on the agent’s name take you to that agent’s profile on the website.

All of the information for the larger display is contained in each of the individual containers. This includes not only the client and agent details, but the video file being used as the HTML video element’s source. Take a look at the HTML of the individual client testimonial containers:

The entire testimonial container is contained in the div with the class testimonial-div. This greater testimonial-div has two children, which are also divs, with the classes testimonial-video and testimonial-info.

  • testimonial-video contains the video element for the testimonial. In the video element, we have the video file, as well as a poster, which acts as the video thumbnail. Click here for more HTML5 video element information.
  • testimonial-info contains the other pertinent information, including the client, their real estate status (buyers or renters) and the agent (or agents) information including their profile page.

*If you are using a component based library, such as React or Vue.js, you can abstract this logic into individual video components contained in a larger VideosContainer component. You could even go as far as to have the testimonial-video’s and testimonial-info’s be separate components within your video component, depending on preference.

We also have another div which will be populated with the user’s chosen testimonial video and information. This target, if you will, is given the class first-testimonial. See the HTML below:

first-testimonial is simply a template. You will see in the JavaScript that all of these empty elements serve a purpose. And that purpose (as is the purpose with any template) is to be empty until populated with information determined by the user’s actions/choices.

  • first-testimonial-video is going to be where we place our testimonial’s video element. This div’s video element will contain the source file and poster which will be provided by whatever individual testimonial div’s first child (video element) contains.
  • first-testimonial-info (you guessed it) is going to be where we place our testimonial’s details. This div’s elements will contain the clients’ names, their real estate status, and what agent they worked with.

This first-testimonial div is essentially a larger testimonial-div. It starts out as nothing (it’s not even visible until the user clicks on a testimonial-div), but provides a larger container for the video (similar to how YouTube’s thumbnails are not, in themselves, the videos, but when clicked lead to the the larger video display).

Now that you’ve seen the HTML context in which we will be working, check out the JavaScript. This is the magic that will make these templates more than just empty shells.

First, I grab all the necessary elements when the page loads, applying the appropriate event listeners.

If you are not familiar with jQuery, please check the documentation for better context.

The closeVideo function is self explanatory, but I will cover the specifics toward the end of the post. The important function is showVideo. See the JavaScript below:

It’s a large function, but here is the first part. We grab this which contains all of the testimonial’s data, contained in two children (remember earlier in the post about the testimonial-divs having two children?).


On line 22442, you can see the JavaScript method cloneNode is called on the testimonial-div that is clicked. We pass true as an argument, this ensures that we also clone the children of the clicked testimonial-div’s first child’s first child (which is the video element-including the source elements). If you don’t do this, then it will only clone the video element without the source element, rendering the video element without a source.

You might remember the scrollTop jQuery animation from my last blog post, which is what’s going on lines 22449–22451. This ensures that when the user selects a testimonial-div the page scrolls back up to the top of the testimonials section of the page.

Lines 22444 through 22446 utilize the ternary operator to determine whether call play() or pause(). If a video is paused, then call play(), otherwise call pause(). So if you a video is being played, execute pause(), and vice versa. This allows the user to click on the first-testimonial container and either pause or play the video.

Are you distracted enough? No? Well, then keep reading.

On line 22453, you can see the conditional checking if the event target tag is an anchor or not. This is to prevent the overall function and just redirect to the agents page. So if you clicked on the agents name (an anchor tag) then don’t execute the rest of the function and just go to the agent’s profile.

The next line is where we start transferring the information from the clicked testimonial div to the-currently empty- master testimonial container. We check the height to ensure that is not currently populated with any cloned node information. If it is not currently populated, then select the specific sections of the first-testimonial div where you want the cloned node information to go and apply styles (display block reveals the div and executes animations).

The second part of this conditional is executed if the height of the first-testimonial div is greater than 10 (you could also do 0, I don’t remember if there was a reason I chose 10 but it doesn’t really matter). If it is greater than 10, this indicates that it already contains another testimonial div’s cloned information. If this is the case then all we want to do is set the innerHTML to an empty string, effectively removing all of the pre-existing cloned node information. Then we add the new information to their specific target nodes, and there’s no need to apply all of the style changes like we did in the first part of the conditional statement. These styles were already applied when we first populated the div with cloned information. If you want to execute the same animations etc. every single time the div is populated as opposed to doing it for the first time (something that I an my supervisors thought was a bit redundant and unnecessary) then you can just execute the same lines in the first part of the conditional again. Why you would want to do that…

…but do what makes you happy. Which brings us to the last part of our video selection interface: closeVideo.

This function is self explanatory in purpose: close the video. So we need change the styles so it is no longer visible. We also remove all of the previously cloned node’s information. We’re returning the first-testimonial div back to it’s empty state #ShellArtIsBack.

And that’s it. To use the interface for yourself check it out here.**

**The site is live at the time this blog was posted. I am not sure when or if it will ever be taken down. I do not work for the company anymore.

If custom JavaScript and HTML5 Video aren’t to your liking, here are a few possible libraries you may prefer:




While these libraries are good for customizing individual video players I am not sure how effective they are at the selection and listing of videos. You could use these in conjunction with my code to create an effective and robust video listing and selection interface.

For a more dynamic implementation, you can create a database video class that contains video objects. These video objects would consist of references to video files and whatever information you want to be rendered with the video object. Fetch the data, and iterate over the returned collection of objects an render the each object as a testimonial component. This is more efficient if you have a larger collection of videos, as opposed to hard coding the video components.

Code 📲💻 Wellness 🧘🏻‍♂️😌

Get the Medium app