Front
The visible side of the card before flipping. It's a centered content area with a white background, rounded corners, and a subtle border. The backface-hidden rule keeps it invisible once the card rotates past 90°.
<div
data-fc="front"
class="relative flex items-center p-8 rounded-2xl bg-white dark:bg-gray-800 text-gray-800 dark:text-gray-100 backface-hidden shadow-lg border border-gray-200 dark:border-gray-700 aspect-(--fc-ar) overflow-auto"
>
<div class="w-full prose dark:prose-invert"><yield /></div>
</div>
Back
The reverse side, absolutely positioned on top of the front so both occupy the same space. It starts pre-rotated 180° on the Y axis, which means it's hidden until the inner container flips to match. A slightly darker background distinguishes it from the front at a glance.
<div
data-fc="back"
class="absolute inset-0 flex items-center p-8 rounded-2xl bg-gray-50 dark:bg-gray-950 text-gray-800 dark:text-gray-100 backface-hidden transform-[rotateY(180deg)] shadow-lg border border-gray-200 dark:border-gray-700 overflow-auto"
>
<div class="w-full prose dark:prose-invert"><yield /></div>
</div>
Flashcard
The outer wrapper that sets up the 3D context. perspective-[1000px] on the container gives the flip a sense of depth. The inner div holds both faces and transitions its rotateY transform when the .flipped class is toggled. An optional ar prop controls the aspect ratio (defaults to square).
<div
class="my-4 w-full max-w-md mx-auto perspective-[1000px]"
style="--fc-ar: {{ ar: 1/1 }}"
>
<div
data-fc="inner"
class="relative cursor-pointer transform-3d transition-transform duration-500 ease-in-out"
>
<yield />
</div>
</div>
<style>
[data-tag="flashcard"] [data-fc="inner"].flipped {
transform: rotateY(180deg);
}
</style>
<script type="text/javascript">
// TODO: this needs to be inside a onmount type of listener e.g.
document.addEventListener("pathmx:ready", function () {
console.log("[flashcards] pathmx:ready event received")
document
.querySelectorAll('[data-tag="flashcard"]:not([data-fc-init])')
.forEach(function (el) {
el.setAttribute("data-fc-init", "")
var inner = el.querySelector('[data-fc="inner"]')
if (!inner) return
inner.addEventListener("click", function () {
inner.classList.toggle("flipped")
})
})
})
</script>
The style rule targets the .flipped state on the inner container, rotating it 180° to reveal the back face. The script finds each flashcard that hasn't been initialized yet, marks it, and attaches a click handler that toggles the flip.
Example
A simple question-and-answer card — click to reveal the answer:
backface-hidden do?