Interactive

Scratch to Reveal

A cover you scratch off with the pointer to uncover whatever sits underneath.

Scratch to Reveal paints a gradient over its slot and then erases that paint where the pointer moves, using the canvas destination-out composite. Scratching is a real stroke rather than a trail of dots, so a fast drag still leaves a continuous line.

The component measures how much of the cover is gone when the pointer lifts, and once that share passes threshold it fades the whole cover out and emits complete. Nothing else is animated, which is why the reveal stays crisp while you drag.

Usage

You won

20% off

Code SCRATCH20

Drag across the card to scratch it off.

<template>
  <MScratchToReveal
    :width="320"
    :height="200"
    :threshold="45"
    class="border border-default"
    @complete="revealed = true"
  >
    <div class="flex flex-col items-center gap-1 text-center">
      <p class="text-xs uppercase tracking-widest text-muted">
        You won
      </p>
      <p class="text-3xl font-bold text-highlighted">
        20% off
      </p>
      <p class="text-xs text-muted">
        Code SCRATCH20
      </p>
    </div>
  </MScratchToReveal>
</template>

Examples

Customize

You won

20% off

Code SCRATCH20

Customize

Brush size24
Gradient Colors
Height200
Threshold45
Width320

Props

Prop Type Default Description
widthnumberundefinedWidth of the frame, in pixels. Left out, the frame fills its parent and the slot decides the height.
heightnumberundefinedHeight of the frame, in pixels. Left out, the slot's content sets it.
brushSizenumber24Radius of the scratch stroke, in pixels. It stays the same size at any display scale.
thresholdnumber50Share of the cover, from 0 to 100, that has to be gone before the rest fades away.
gradientColorsstring[]['#a97cf8', '#f38cb8', '#fdcc92']Colours the cover fades through, corner to corner.
classstring''CSS classes for the frame.

Events

Event Payload Description
complete-Fired once the scratched area passes threshold. It does not fire again until reset() is called.

Slots

Slot Props Description
default-Content under the cover. It is always in the document, so a screen reader can read it before anyone scratches anything.

Methods

Prop Type Default Description
reset() => void-Paints the cover back and clears the revealed state, ready to be scratched again.
<template>
  <MScratchToReveal ref="scratch">
    <p>Under the cover</p>
  </MScratchToReveal>
  <UButton @click="scratch?.reset()">
    Play again
  </UButton>
</template>

UI

This component's theme exposes the slots below. Override any of them per instance with the ui prop, or app-wide under ui.scratchToReveal in app.config.ts.

Prop Type Default Description
uiobject-Per-slot classes merged over the theme defaults.
Slot Props Description
root-relative w-full select-none overflow-hidden rounded-xl
content-flex size-full items-center justify-center
canvas-absolute inset-0 size-full cursor-crosshair touch-none transition-opacity duration-500

Accessibility

The cover is a canvas with aria-hidden, and the content underneath is ordinary DOM that is never removed, so nothing has to be uncovered to be read or found by search. Scratching is pointer-only, which is why the prize should not be a secret that only appears on success: the reveal is a flourish on top of information that is already in the page. On touch screens the canvas sets touch-action: none, so a drag scratches instead of scrolling the page.

Copyright © 2026