<div class="vegetables">
	<div class="inner">
		<ul class="page">
			<li><span>Carrot</span></li>
			<li><span>Tomato</span></li>
			<li><span>Broccoli</span></li>
			<li><span>Cucumber</span></li>
			<li><span>Spinach</span></li>
		</ul>
		<!-- Page 1 -->

		<ul class="page">
			<li><span>Potato</span></li>
			<li><span>Pepper</span></li>
			<li><span>Eggplant</span></li>
			<li><span>Lettuce</span></li>
			<li><span>Onion</span></li>
		</ul>
		<!-- Page 2 -->

		<ul class="page">
			<li><span>Zucchini</span></li>
			<li><span>Cauliflower</span></li>
			<li><span>Kale</span></li>
			<li><span>Cabbage</span></li>
			<li><span>Mushroom</span></li>
		</ul>
		<!-- Page 3 -->

		<ul class="page">
			<li><span>Asparagus</span></li>
			<li><span>Artichoke</span></li>
			<li><span>Radish</span></li>
			<li><span>Beet</span></li>
			<li><span>Okra</span></li>
		</ul>
		<!-- Page 4 -->

		<ul class="page">
			<li><span>Brussels Sprouts</span></li>
			<li><span>Green Bean</span></li>
			<li><span>Butternut Squash</span></li>
			<li><span>Turnip</span></li>
			<li><span>Chard</span></li>
		</ul>
		<!-- Page 5 -->
	</div>
</div>
<div class="pagination">
	<ul id="dots">
		<li class="prev"></span></li>
		<li></li>
		<li></li>
		<li></li>
		<li></li>
		<svg width="430" height="200" viewBox="0 0 400 200">
			<path></path>
		</svg>
	</ul>
	<button id="prevPage">Previous</button>
	<button id="nextPage">Next</button>
</div>
@font-face {
	font-family: "Romie";
	src: url("https://assets.codepen.io/383755/Romie-Regular.woff2")
		format("woff2");
}

body {
	font-family: sans-serif;
	max-width: 100vw;
	height: 100vh;
	position: relative;
	overflow: hidden;
	--black: #151515;
	--c1: #0272f2;
	--c2: #ff5213;
	--c3: #ffdf3f;
	--c4: #01b26e;
	--c5: #fea9e0;
	--c6: #ffdf3f;
	background: var(--black);
}

.vegetables {
	perspective: 500px;
	transform-style: preserve-3d;
	display: flex;
	flex-wrap: wrap;
	justify-content: space-between;
	width: 100vw;
	height: 100%;
	position: absolute;
	top: 0;
	left: 0;
	margin: 0 auto;
	font-family: "Romie";
	* {
		transform-style: preserve-3d;
	}
	.inner {
		position: absolute;
		width: 100vw;
		height: 100vh;
	}
}

.page {
	transform-style: preserve-3d;
	position: absolute;
	top: calc(50% - 100px);
	left: 50%;
	list-style: none;
	padding: 0;
	height: calc(90vmin - 300px);
	width: 90vmin;
	display: flex;
	justify-content: center;
	align-items: stretch;
	flex-wrap: wrap;
	gap: 10px;
	padding: 0;
	margin: 0;
	transform: translate(-50%, -50%) translateZ(200vmin);
	transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1) 0.75s;
	li {
		transition: 0.5s ease-in-out;
		opacity: 0;
		font-size: 7vmin;
		@for $i from 1 through 5 {
			&:nth-of-type(#{$i}) {
				color: #ccc;
				span:after {
					transform: scaleX(0);
					background: #ccc;
					transition: 0.5s ease-in-out #{($i/8) + 0.75}s;
				}
			}
		}
	}
	&.current {
		transform: translate(-50%, -50%) translateZ(0vmin);
		li {
			opacity: 1;
			background-position: 50% 100%;
			@for $i from 1 through 5 {
				&:nth-of-type(#{$i}) {
					transition: 0.5s ease-in-out 0.75s, color 0.5s ease-in-out #{($i/8) + 1}s;
					color: var(--c#{$i});
					span:after {
						transform: scaleX(1);
						background: var(--c#{$i});
						transition: 0.5s ease-in-out #{($i/8) + 0.75}s;
					}
				}
			}
		}

		&:nth-of-type(even) li {
			@for $i from 1 through 5 {
				&:nth-of-type(#{$i}) {
					color: var(--c#{6 - $i});
					span:after {
						background: var(--c#{6 -$i});
					}
				}
			}
		}
	}
}

.page li {
	display: flex;
	justify-content: flex-start;
	align-items: center;
	width: 100%;
	overflow: hidden;
	span {
		display: inline-block;
		position: relative;
		background: var(--black);
		&:after {
			content: "";
			position: absolute;
			width: 100vw;
			left: calc(100% + 1rem);
			top: calc(50% - 0.5px);
			height: 1px;
			background: #ccc;
			z-index: -1;
		}
	}
	&:nth-of-type(even) {
		justify-content: flex-end;
		span {
			&:after {
				left: auto;
				right: calc(100% + 1rem);
			}
		}
	}
}

.pagination {
	text-align: center;
	margin-top: 20px;
	position: absolute;
	bottom: 0;
	left: 0;
	width: 100%;
	padding: 1rem;
}

button {
	padding: 8px 16px;
	border: 1px solid #ccc;
	background: transparent;
	color: #ccc;
	cursor: pointer;
	margin: 0 7.5px 1rem;
	position: relative;
	z-index: 999;
	width: 200px;
	border-radius: 50px;
	transition: 0.3s ease-in-out;
	font-family: "Romie";
	font-size: 1.15rem;
	padding: 0.15rem;
	font-weight: 900;
}

button:hover {
	border-color: var(--c3);
	color: var(--c3);
}

button:disabled {
	border-color: #666;
	color: #666;
	cursor: not-allowed;
}

#dots {
	--timing: 0.75;
	width: 400px;
	list-style-type: none;
	position: absolute;
	top: -150px;
	height: 200px;
	left: 50%;
	transform: translate(-50%);
	padding: 0;
	margin: 0;
	--basepath: "M 0 100 Q 200 100 400 100 ";
	--basepath-1: "M 0 150 Q 100 100 400 100 ";
	--basepath-2: "M 0 100 Q 100 200 400 100 ";
	--basepath-3: "M 0 100 Q 200 200 400 100 ";
	--basepath-4: "M 10 100 Q 300 200 400 100 ";
	--basepath-5: "M 10 100 Q 300 100 400 150 ";
	@for $i from 1 through 5 {
		--placement-#{$i}: #{(($i - 1) * 100) - 5}px;
		&:has(li:nth-of-type(#{$i}).active) {
			@for $j from 1 through 5 {
				&:has(li:nth-of-type(#{$j}).prev) {
					--origin: var(--placement-#{$j});
					--destination: var(--placement-#{$i});
					svg path {
						animation: spring#{$j} 0.75s ease-in-out 1 forwards;
						@keyframes spring#{$j} {
							75% {
								d: path(var(--basepath-#{$j}));
								animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.875);
							}
							100% {
								d: path(var(--basepath));
								animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.875);
							}
						}
					}
					li {
						animation: bounce#{$j} 0.75s ease-in-out 1 forwards;
						@keyframes bounce#{$j} {
							75% {
								offset-path: path(var(--basepath-#{$j}));
								animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.875);
							}
							100% {
								offset-path: path(var(--basepath));
								animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.875);
							}
						}
						&:before {
							animation: shift#{$j}
									calc(0.35s * var(--timing))
									ease-out
									1
									forwards
									0.6s,
								jump#{$j} calc(0.35s * var(--timing)) linear 1 forwards 0.6s;
							@keyframes shift#{$j} {
								100% {
									transform: translateX(calc(var(--destination) - var(--origin)));
								}
							}
							@keyframes jump#{$j} {
								25%,
								75% {
									top: calc(-50px * (var(--timing) * 0.75));
								}
								50% {
									top: calc(-50px * (var(--timing) * 1.25));
								}
								33%,
								66% {
									top: calc(-50px * (var(--timing) * 1));
								}
							}
						}
					}
				}
			}
		}
	}
}

svg {
	position: absolute;
	left: 50%;
	top: 50%;
	transform: translate(-50%, -50%);
	z-index: -1;
	stroke-linecap: round;
	filter: drop-shadow(0 5px 10px rgba(0, 0, 0, 0.25));
	path {
		stroke-width: 25px;
		stroke: var(--c1);
		fill: none;
		d: path(var(--basepath));
	}
}

#dots li {
	width: 10px;
	height: 10px;
	background: var(--black);
	box-shadow: 0 0 0 3px var(--black);
	border-radius: 100%;
	offset-path: path(var(--basepath));
	position: absolute;
	cursor: pointer;
	&:hover {
		box-shadow: 0 0 0 2px var(--black), 0 0 0 3px var(--c5);
	}
	&:before {
		content: "";
		position: absolute;
		width: 100%;
		height: 100%;
		background: var(--c5);
		left: 0;
		top: 0;
		border-radius: 100%;
		opacity: 0;
		z-index: 999;
		pointer-events: none;
	}
	&.active {
		pointer-events: none;
	}
	&.prev {
		z-index: 9;
		&:before {
			opacity: 1;
		}
	}
	@for $i from 1 through 5 {
		&:nth-of-type(#{$i}) {
			offset-distance: calc(#{($i - 1) * 25} * 1%);
		}
	}
}
View Compiled
document.addEventListener("DOMContentLoaded", function () {
	const pages = document.querySelectorAll(".page");
	const prevButton = document.getElementById("prevPage");
	const nextButton = document.getElementById("nextPage");
	let currentPage = 0;

	function showPage(pageNumber) {
		pages.forEach((page, index) => {
			page.classList.remove("current");
			pages[pageNumber].classList.add("current");
			document.body.style.setProperty("--shift", pageNumber);
		});
	}

	function updateButtons() {
		prevButton.disabled = currentPage === 0;
		nextButton.disabled = currentPage === pages.length - 1;
	}

	prevButton.addEventListener("click", function () {
		if (currentPage > 0) {
			currentPage--;
			showPage(currentPage);
			updateButtons();
			document.querySelectorAll("#dots li")[currentPage].click();
		}
	});

	nextButton.addEventListener("click", function () {
		if (currentPage < pages.length - 1) {
			currentPage++;
			showPage(currentPage);
			updateButtons();
			document.querySelectorAll("#dots li")[currentPage].click();
		}
	});

	showPage(currentPage);
	updateButtons();

	let dotNav = document.getElementById("dots"),
		newIndex = 0,
		prevIndex;

	document.querySelectorAll("#dots li").forEach((dot, index) => {
		dot.addEventListener("click", function (e) {
			currentPage = index;
			showPage(currentPage);
			if (document.getElementsByClassName("active")[0]) {
				prevIndex = newIndex;
				newIndex = index;
				updateButtons();
				dotNav.style.setProperty(
					"--timing",
					Math.abs((newIndex - prevIndex) / 5) + 0.5
				);
				document.getElementsByClassName("prev")[0] &&
					document.getElementsByClassName("prev")[0].classList.remove("prev");
				document.getElementsByClassName("active")[0].classList.add("prev");
				document.getElementsByClassName("active")[0].classList.remove("active");
			}
			e.target.classList.add("active");
		});
	});
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.