Ticket Stub
loomui/ticket-stubFreeComponent
A card torn along a perforation, with a notch bitten out of the paper at each end of it.
Live preview
live · rendered by the registry
Rendered by loomui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://loomui.design/r/ticket-stub.jsonSource
1"use client"23import * as React from "react"45import { cn } from "@/lib/utils"67export interface TicketStubProps extends React.ComponentProps<"div"> {8 /** The torn-off part. Sits after the perforation. */9 stub?: React.ReactNode10 /** Where the perforation falls, as a percentage of the long side. */11 split?: number12 /** Radius of the notches bitten out at each end of the tear, in pixels. */13 notch?: number14 /** Stub on the right of a wide ticket, or below a tall one. */15 orientation?: "horizontal" | "vertical"16 /** Lift the ticket off the page on hover. */17 lift?: boolean18}1920export function TicketStub({21 children,22 stub,23 split = 68,24 notch = 12,25 orientation = "horizontal",26 lift = true,27 className,28 style,29 ...props30}: TicketStubProps) {31 const vertical = orientation === "vertical"3233 // Two circles cut out of the same shape. Intersecting the masks is what takes34 // a bite from both ends of the tear instead of only the last one declared.35 const mask = vertical36 ? `radial-gradient(circle at left ${split}%, transparent ${notch}px, #000 ${notch + 0.5}px), radial-gradient(circle at right ${split}%, transparent ${notch}px, #000 ${notch + 0.5}px)`37 : `radial-gradient(circle at ${split}% top, transparent ${notch}px, #000 ${notch + 0.5}px), radial-gradient(circle at ${split}% bottom, transparent ${notch}px, #000 ${notch + 0.5}px)`3839 // Everything the edge is made of lives out here. A `box-shadow` or a `border`40 // on the masked element is cut away with the paper, which leaves the notches41 // unoutlined, and on a dark background an edge drawn only in shadow is not42 // an edge at all. Four offset drop shadows trace the alpha instead, so the43 // outline follows the curve of every bite.44 const edge = [45 "drop-shadow(0 1px 0 var(--border))",46 "drop-shadow(0 -1px 0 var(--border))",47 "drop-shadow(1px 0 0 var(--border))",48 "drop-shadow(-1px 0 0 var(--border))",49 "drop-shadow(0 4px 10px rgb(0 0 0 / 0.14))",50 ].join(" ")5152 return (53 <div54 data-slot="ticket-stub"55 className={cn(56 "relative",57 lift &&58 "ease transition-transform duration-200 hover:-translate-y-1 hover:rotate-[-0.4deg] motion-reduce:transition-none",59 className60 )}61 style={{ filter: edge, ...style }}62 {...props}63 >64 <div65 className={cn(66 "bg-card text-card-foreground flex overflow-hidden rounded-xl",67 vertical ? "h-full flex-col" : "w-full flex-row"68 )}69// … truncated
What it pulls in
Other registry items
Files it writes
More from loomui
All 91 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Aurora Backdropaurora-backdrop | loomui | Components | Free | no deps | |
| Bento Gridbento-grid | loomui | Components | Free | no deps | |
| Card Stackcard-stack | loomui | Components | Free | no deps | |
| Compare Slidercompare-slider | loomui | Components | Free | no deps | |
| Confetti Buttonconfetti-button | loomui | Components | Free | no deps | |
| Count Upcount-up | loomui | Components | Free | no deps | |
| Credit Cardcredit-card | loomui | Components | Free | no deps | |
| Drawerdrawer | loomui | Components | Free | 1 dep |
