Categories

Expanding Cards (Vanilla JS)
Jeremy Threlfall

Jeremy Threlfall

Aug 10, 2025

Expanding Cards (Vanilla JS)

A small interactive project built with HTML, CSS, and JavaScript. It uses querySelectorAll and event listeners to toggle classes on click, with a CSS transition for smooth, animated style changes.

Live Demo | GitHub

HTML:

In the HTML, I created a main wrapper <div> with the class container to hold all the panels. Inside this container, there are five <div> elements each with the class panel. The first panel also has an additional class active, which is the one initially expanded when the page loads. Each panel has an inline style to set a background image and contains an <h3> heading for the panel title.

The active class on the first panel triggers its expanded state by default. When users interact with the panels, JavaScript toggles this class to expand or collapse them accordingly.

<div class="container">
  <div class="panel active" style="background-image: url('linkForImageHere');">
    <h3>Panel 1</h3>
  </div>
  <div class="panel" style="background-image: url('linkForImageHere');">
    <h3>Panel 2</h3>
  </div>
  ...
  <div class="panel" style="background-image: url('linkForImageHere');">
    <h3>Panel 5</h3>
  </div>
</div>
CSS:

I included all of the custom styles, but will only outline the most important for the funtionality of the project. The .container uses a flexbox layout to arrange the panels side-by-side, occupying 90% of the viewport width. Each .panel starts with a small flexible size (flex: 0.5), a background image that covers the panel area, and rounded corners for a smooth look. When a panel has the active class, it expands significantly (flex: 5), with a smooth transition animating the size change over 0.7 seconds. Inside each panel, the <h3> heading is positioned near the bottom center but initially hidden (opacity: 0). When the panel is active, the heading fades in (opacity: 1) to draw attention.

To keep the layout clean on smaller screens (under 480px wide), a media query adjusts the container width to full viewport width and hides the fourth and fifth panels, showing only the first three.

.container {
	display: flex;
	width: 90vw;
	color: #fff;
}

.panel {
	background-size: cover;
	background-position: center;
	background-repeat: none;
	height: 80vh;
	border-radius: 50px;
	cursor: pointer;
	flex: 0.5;
	margin: 10px;
	position: relative;
	transition: flex 0.7s ease-in;
}

.panel h3 {
	font-size: 24px;
	position: absolute;
	bottom: 20px;
	left: 50%;
	opacity: 0;
}

.panel.active {
	flex: 5;
}

.panel.active h3 {
	opacity: 1;
}

/* on smaller screens, only show 3 at a time */
@media (max-width: 480px) {
	.container {
		width: 100vw;
	}

	.panel:nth-of-type(4),
	.panel:nth-of-type(5) {
		display: none;
	}
}
JavaScript:

First, I select all the panels by using document.querySelectorAll to target elements with the .panel class and store them in the cards NodeList.

Next, I define the showSelectedCard function, which takes an index i as its argument. This function loops through all the cards, and for each card, it checks if the card’s index matches i. If it does, it adds the active class to that card, expanding it. If not, it removes the active class, collapsing any other expanded card.

Finally, I add a click event listener to each card in the cards list. When a card is clicked, it calls showSelectedCard with that card’s index, causing the clicked card to expand while collapsing the others.

This simple approach allows only one panel to be expanded at a time, creating an interactive and smooth user experience.

const cards = document.querySelectorAll('.panel');

const showSelectedCard = (i) => {
	cards.forEach((card, index) => {
		index === i
			? card.classList.add('active')
			: card.classList.remove('active');
	});
};

cards.forEach((card, i) => {
	card.addEventListener('click', () => showSelectedCard(i));
});
Final Thoughts:

This expanding cards project is a perfect example of how a little bit of HTML, CSS, and JavaScript can come together to create something that feels polished and fun to use. The flexbox layout keeps everything nice and flexible, while the smooth transitions make the panels open and close in a way that just feels right. And the JavaScript? It’s simply just toggling classes, but it gets the job done without any fuss.

What’s cool is that this kind of interaction isn’t just for show; you can use it in all sorts of ways, like image galleries, feature spotlights, or even navigation menus. It’s a neat little pattern that’s worth having in your front-end toolkit. Playing around with it is also a great way to get more comfortable with how CSS and JavaScript work hand in hand.

If you’re up for it, there’s plenty of room to build on this. Maybe add keyboard navigation, load content dynamically, or experiment with some fancier animations. Once you get the basics down, the possibilities are pretty much endless!

author.name

Jeremy Threlfall

Jeremy is a Fullstack Developer. Originally from the United States, he currently resides in Taiwan, and works freelance remotely.

Portfolio

Leave a Comment (will be submitted for review)

Related Posts

Categories