I am trying to create a scroll container for cards where the scroll is performed in the card content only, not in the header or footer. I guess that the container should hide the horizontal overflow and the card should have overflow-y: auto
. However, doing so causes that the following cards are not visible.
function MainComponent() {
const [activeCardIndex, setActiveCardIndex] = React.useState(0);
const cardsContainerRef = React.useRef(null);
const cardsRefs = React.useRef([]);
const updateLayoutOffset = React.useCallback(() => {
if (!cardsContainerRef.current || !cardsRefs.current[activeCardIndex]) {
return 0;
}
const storyWidth = cardsRefs.current[activeCardIndex].offsetWidth;
const containerWidth = cardsContainerRef.current.offsetWidth;
let offset = containerWidth / 2 - storyWidth / 2 - activeCardIndex * storyWidth - activeCardIndex * 8;
cardsContainerRef.current.style.transform = `translateX(${offset}px)`;
}, [activeCardIndex]);
React.useLayoutEffect(() => {
updateLayoutOffset();
}, [updateLayoutOffset]);
React.useEffect(() => {
updateLayoutOffset();
}, [activeCardIndex, updateLayoutOffset]);
const goToNextCard = React.useCallback(() => {
if (activeCardIndex === cardsRefs.current.length - 1) {
return;
}
setActiveCardIndex(activeCardIndex + 1);
}, [activeCardIndex]);
const goToPreviousCard = React.useCallback(() => {
if (activeCardIndex === 0) {
return;
}
setActiveCardIndex(activeCardIndex - 1);
}, [activeCardIndex]);
let cards = ["Card 1", "Card 2", "Card 3"];
return (
<div className="flex h-dvh max-h-dvh w-full max-w-full flex-col justify-center overflow-hidden bg-black px-2 py-1 sm:bg-[#1a1a1a] sm:py-3">
<div className="flex h-full max-h-full flex-row transition-transform duration-500">
<div className="flex h-full max-w-full flex-row items-center sm:gap-4">
<button className="rounded-md bg-blue-500 p-2 text-white" onClick={goToPreviousCard}>
Previous
</button>
<div className="flex aspect-[9/16] h-full max-h-full max-w-full flex-col rounded-md bg-black">
<div className="flex flex-col gap-2 p-2">
<h1 className="h-fit flex-1 text-left leading-none text-white">Header </h1>
</div>
<div ref={cardsContainerRef} className="flex grow flex-row items-center gap-2 overflow-y-auto overflow-x-clip transition-transform duration-500">
{cards.map((card, index) => (
<div
ref={(el) => {
if (el) {
cardsRefs.current[index] = el;
}
}}
key={index}
className="relative flex h-full min-w-full max-w-full flex-col gap-2 overflow-y-auto text-pretty rounded-md bg-white p-2 dark:bg-[#343434]"
>
{Array(40)
.fill(0)
.map((_, i) => (
<p key={i} className="text-center">
{card}
</p>
))}
</div>
))}
</div>
<div className="flex w-full flex-row items-center p-2">
<input className="min-w-0 flex-1 rounded-full border-[1px] bg-transparent px-4 py-2 text-left" />
</div>
</div>
<button className="rounded-md bg-blue-500 p-2 text-white" onClick={goToNextCard}>
Next
</button>
</div>
</div>
</div>
);
}
ReactDOM.createRoot(document.getElementById("root")).render(<MainComponent />);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>
I can not find any combination of overflow settings that works fine.
2
Answers
Solution 1:
overflow-x: clip
from the cards container and replaced itwith
overflow-visible
to ensure other cards are visibleoverflow-y-auto
from the card itself to this inner containerSolution 2:
overflow-y-auto
only on the inner content of each card instead ofthe card container. This will allow vertical scrolling only for each
card’s inner content without affecting the main card container’s
layout.
overflow-x-hidden
on the main container (cardsContainerRef). Thiswill ensure any overflowing content horizontally doesn’t affect the
rest of the layout.
I had same challenge in my project and I tried to change my code based on your implementation.
here is the MainComponent
Button.tsx Component:
Input.tsx component
Card.tsx component