25
Componentregistry:component

Tear Reveal

A sheet of paper over any content that you tear open by dragging from a notch. The tear follows your path with a jagged edge and a pale fibrous rim, the halves fall away with gravity and spin past a threshold, and an early release springs it shut. Enter or Space tears it in one pass.

Installation

$ npx shadcn@latest add @creative-ui/tear-reveal

On an older shadcn CLI, use the URL: npx shadcn@latest add https://ui.krutikraut.com/r/tear-reveal.json

Preview

Painting of a woman carrying a water jar

The Water Carrier

Oil on canvas, gallery four

Direction
Paper

Usage

Example.tsx
import { TearReveal } from "@/components/tear-reveal"

export function Ticket() {
  return (
    <TearReveal
      cover={<p className="grid size-full place-items-center font-serif text-2xl">Admit one</p>}
      className="aspect-[3/4] w-72 rounded-md"
    >
      <img src="/painting.jpg" alt="The painting behind the ticket" className="size-full rounded-md object-cover" />
    </TearReveal>
  )
}

// Controlled, with a reset.
const [torn, setTorn] = React.useState(false)

<TearReveal torn={torn} onTear={() => setTorn(true)} direction="corner" paper="#387478">
  <Prize />
</TearReveal>
<button onClick={() => setTorn(false)}>Reset</button>

Props

PropTypeDefaultDescription
coverReact.ReactNode—What is printed on the paper: a label, an image, any node. It fills the sheet and inherits an ink colour that reads on paper, so currentColor works for text and rules. Omit for blank paper.
childrenReact.ReactNode—The content under the paper. It is inert until the paper is torn.
direction"down" | "across" | "corner""down"Where the tear starts. down runs from a notch in the top edge, across from the left edge, corner from the top-right corner.
paperstring"#f4f1ea"Paper colour, as hex. The torn rim is a lighter mix of it, the way coloured paper is white inside.
thresholdnumber0.4How far the tear must run before letting go tears it free, 0 to 1 of the way across. A quick flick in the tear direction also counts.
tornboolean—Controlled torn state. Set it back to false to put the paper back.
defaultTornbooleanfalseInitial torn state when uncontrolled.
onTear() => void—Called when the paper tears free by drag or keyboard. Not called when torn is set from outside.
seednumber5Seed for the jagged edge and the way the halves fall. Change it on reset for a fresh tear.
labelstring"Tear to reveal"Accessible name for the cover.

Also accepts every div prop, which is spread onto the root element.

Notes

  • Size the component with className, or let children size it. The cover always matches the content box.
  • Only the notch handle captures touch, with touch-action: none, so the rest of the card still scrolls the page.
  • The cover is a button. Enter or Space tears it in one automatic pass and moves focus to the content.
  • With reduced motion the drag still works, but the paper fades out instead of falling.
  • The halves fall outside the component's box. Add overflow-hidden to the root if they must stay inside.
  • cover is rendered twice, once per half, so keep it presentational. Images in it load once and are reused from cache.
  • When controlled, set torn to true in onTear. If it stays false, a fresh sheet comes back after the fall.

Dependencies

shadcn/utils