A cards carousel with swipe gestures, loopable or not. This is an interaction pioneered by Tinder and that is not so common in desktop apps. It’s so much fun to use, go ahead and drag / swipe cards around and see what happens.






6 cards
Open the repo in Github (and drop a star if you like it!)
npm install @daformat/react-swipeable-cardsBelow is a minimal example to reproduce the examples above, view the full tsx and scss on github
// full source: https://github.com/daformat/hello-mat/blob/master/pages/design-engineering/component/swipeable-cards.tsx
<SwipeableCards.Root
cards={[...cards /* omitted for brevity */ ]}
className={styles.cards_root}
data-style={"stacked-offset" /* "stacked-rotation" | "minimal" */}
swipeStyle={"sendToBack"}
sendToBackMargin={16}
loop
>
<SwipeableCards.Cards
visibleStackLength={4}
style={{ aspectRatio: "650 / 400" }}
/>
</SwipeableCards.Root>Performing swipe gestures on the web is not a native feature, so you’ll have to do it yourself. The gist of it is to translate the card as you drag it, and compute the velocity of the swipe for a realistic momentum to be applied as you discard a card. This is done simply by dividing the distance traveled by the card by the amount of time elapsed since the last pointer move event.
If you drag a card just a little a bit and release the pointer, the card will return to the stack. Unless you moved it by some minimal distance. In this case, we need to ”fake“ the velocity so the card properly animates out of the viewport.
When using buttons, the user didn’t actually perform a swipe gesture, so we need to simulate it. We do this by mocking the dragging state, so that the card properly animates out.
When sending the cards to the back of the stack, we need to ensure the swiped card has travelled enough so that when swapping its z-index, the card doesn’t overlap the stack. Many implementations disregard this issue, as this is not trivial to implement. This package properly ensures that, no more partial clipping when sending a card to the bottom of the stack!
The component allows you to customize the margin by using the sendToBackMargin prop, which is used to specify the pixels-based distance to enforce when sending a card to the back.
I was curious to see how I would implement this, so I settled on finding out. I’m overall pretty pleased with the result, and I think I’ll re-use the component in the future. There is something deeply satisfying in using this interaction, and I think Tinder made it their landmark for a reason.