Ticket Stub Card
A ticket card with a perforated dotted line and side notches; click to tear off the stub.
A two-part ticket card of main ticket and stub, with semicircular notches and a perforated dotted line at the seam to mimic a real ticket stub; clicking the stub tears it along the perforation, spinning and fluttering away as an admitted stamp lands on the main ticket. A good fit for event tickets, coupons, boarding passes, and similar cases.
Bring this into your project
Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.
npx webberui@latest add ticket-stub-card.enPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<TicketStubCard/>
The complete example includes the preview layout and data. Install the component first, then paste this file into your project.
Installation
npx webberui@latest add https://webberui.com/r/ticket-stub-card.en.jsonOr, once registries are configured in components.json, install it as @webberui/ticket-stub-card.
Usage
import { TicketStubCard } from "@/components/ui/ticket-stub-card";
<TicketStubCard
stub={<span className="font-bold">A-12</span>}
onTear={() => console.log("Torn off!")}
>
<h3 className="text-xl font-bold">A Night of Jazz Under the Moon</h3>
<p className="text-sm text-neutral-500">2026/08/22 19:30</p>
</TicketStubCard>Props
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | — | Content of the main ticket area (event name, time, venue, and so on) |
stub | React.ReactNode | — | Content of the stub area (seat, ticket number, and so on) |
onTear | () => void | — | Callback fired when the stub is torn off |
torn | boolean | — | Controlled torn state; when omitted, the component manages it internally |
stubWidth | number | 128 | Stub width (px) |
notchRadius | number | 12 | Radius of the semicircular perforation notches (px) |
tearHint | string | "Click to Tear Off" | Tear hint text at the top of the stub (the English source includes this default — pass this prop to word it in your own language) |
stampText | string | "Entered" | Stamp text applied to the main ticket after tearing (the English source includes this default); an empty string hides it |
showBarcode | boolean | true | Whether to show the decorative barcode at the bottom of the stub |
tilt | boolean | false | Enables pointer-following 3D tilt (perspective 1100px, ±6°, 1.018 hover scale, 220ms); only applies to fine pointers without reduced motion |
notchSize | number | — | Semicircle notch radius cut with clip-path (px); replaces the mask approach when set, and clicks pass through the notches |
cornerSize | number | 0 | Chamfer size of the outer corners (px); above 0 switches to clip-path, with notches from notchSize (or notchRadius if unset) |
className | string | — | Forwarded to the outermost container |
How it works
3D tilt
With tilt, the whole ticket leans toward the pointer as it moves (up to ±6°, 1100px perspective) and scales to 1.018; on leave it settles back on the same 220ms curve. Whether it turns on is read with useSyncExternalStore from (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference); the server always treats it as off, and touch devices or users with reduced motion never see the tilt.
<TicketStubCard tilt stub={<span className="font-bold">A-12</span>}>
…
</TicketStubCard>clip-path notches and chamfers
By default the notches are drawn with a CSS mask; setting notchSize or cornerSize switches to a clip-path polygon (positioned with calc(100% - Npx), so nothing is measured). clip-path also clips the hit area, so clicks pass through the notches to whatever sits below; cornerSize chamfers the outer corners for a boarding-pass or voucher outline. Without these two props the visuals are identical to earlier versions.
<TicketStubCard notchSize={14} cornerSize={10} stub={<span>B12</span>}>
…
</TicketStubCard>Accessibility
- The stub is a native
buttonelement, focusable with Tab and tearable with Enter / Space, with afocus-visiblefocus ring - When the user has "reduce motion" enabled at the system level, the tear becomes a plain fade out with no spin-and-flutter animation
- The stamp shown after tearing carries
role="status", so assistive technology announces the change in admission state - The barcode, the perforated dotted line, and the paper texture are all decorative elements, hidden from assistive technology with
aria-hidden tiltonly turns on for hover-capable fine pointers when the system "reduce motion" setting is off; with reduced motion there is no tilt or scale at all