Flashcard Tags

A flip-card component for study-style content. Each card has a front and back face — click to flip. The 3D rotation uses CSS perspective and backface-hidden so only one side is visible at a time.

See the flashcards demo for a full example.

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:

What does CSS backface-hidden do?
It hides an element when it's rotated away from the viewer, so only one face of a flip card is visible at a time.