Componentticket-stub1.39 KB gzipZero dependencies
Ticket Card
Complete admission ticket with notched edges and seat details.
Preview
Live Preview
ADMIT ONENO. 08421
BIGBULL MAIN STAGE
SECA
ROWC
SEAT12
GATE3
2026-09-05 · 20:00$45.00
STUB
BIGBULL MAIN STAGE
R: C · S: 12
valid
BB84210
Installation
Tokens guide →Add to your project via CLI (zero dependencies, code you own):
npx bigbullui add ticket-cardOr install the full npm package:
npm install bigbulluiUsage
Open in StackBlitzimport { TicketCard } from "@/components/ui/ticket-card";
<TicketCard
eventName="BIGBULL MAIN STAGE"
status="valid"
price="$45.00"
/>Usage guidance
Use Ticket Card when a ticket stub surface needs Complete admission ticket with notched edges and seat details. Keep props minimal and prefer composition with sibling stubs.
Avoid Ticket Card for long form flows or dense data grids where a dedicated layout block fits better.
Source code
ticket-card.tsxZero dependencies (only React + utils). Copy and paste directly into your project:
import * as React from "react";
import { cn } from "./lib/utils";
export interface TicketCardProps extends React.HTMLAttributes<HTMLDivElement> {
serial?: string;
eventName?: string;
admitCount?: string;
seatInfo?: { row?: string; seat?: string; section?: string; gate?: string };
date?: string;
time?: string;
price?: string;
barcodeValue?: string;
status?: "admitted" | "valid" | "void";
className?: string;
}
export function TicketCard({
serial = "NO. 08421",
eventName = "BIGBULL MAIN STAGE",
admitCount = "ADMIT ONE",
seatInfo = { section: "A", row: "C", seat: "12", gate: "3" },
date = "2026-09-05",
time = "20:00",
price = "$45.00",
barcodeValue = "BB84210",
status = "valid",
className,
...props
}: TicketCardProps) {
return (
<div
className={cn(
"relative flex flex-col md:flex-row overflow-hidden rounded-xl border-2 border-foreground bg-card shadow-md transition-transform hover:-translate-y-0.5",
className
)}
{...props}
>
{/* Main Ticket Portion */}
<div className="flex-1 p-6 md:p-8 flex flex-col justify-between">
<div>
<div className="flex items-center justify-between">
<span className="font-mono text-xs font-bold uppercase tracking-[0.2em] text-accent">
{admitCount}
</span>
<span className="font-mono text-xs text-muted-foreground">{serial}</span>
</div>
<h2 className="mt-3 text-2xl font-bold tracking-tight text-foreground sm:text-3xl">
{eventName}
</h2>
</div>
{/* Seat Grid */}
<div className="mt-6 grid grid-cols-4 gap-2 border-y-2 border-dashed border-border py-4 text-center">
<div>
<span className="block font-mono text-[10px] uppercase tracking-wider text-muted-foreground">
SEC
</span>
<span className="font-mono text-sm font-bold text-foreground">
{seatInfo.section || "—"}
</span>
</div>
<div>
<span className="block font-mono text-[10px] uppercase tracking-wider text-muted-foreground">
ROW
</span>
<span className="font-mono text-sm font-bold text-foreground">
{seatInfo.row || "—"}
</span>
</div>
<div>
<span className="block font-mono text-[10px] uppercase tracking-wider text-muted-foreground">
SEAT
</span>
<span className="font-mono text-sm font-bold text-foreground">
{seatInfo.seat || "—"}
</span>
</div>
<div>
<span className="block font-mono text-[10px] uppercase tracking-wider text-muted-foreground">
GATE
</span>
<span className="font-mono text-sm font-bold text-foreground">
{seatInfo.gate || "—"}
</span>
</div>
</div>
<div className="mt-4 flex items-center justify-between text-xs text-muted-foreground font-mono">
<span>{date} · {time}</span>
<span className="font-bold text-foreground">{price}</span>
</div>
</div>
{/* Perforation Divider with Punch Notches */}
<div className="relative flex md:flex-col items-center justify-between md:py-0">
{/* Top/Left notch */}
<div className="size-5 rounded-full bg-background border-2 border-foreground -ms-2.5 md:ms-0 md:-mt-2.5 shrink-0" />
{/* Dashed line */}
<div className="h-0 w-full md:w-0 md:h-full border-t-2 md:border-t-0 md:border-l-2 border-dashed border-border" />
{/* Bottom/Right notch */}
<div className="size-5 rounded-full bg-background border-2 border-foreground -me-2.5 md:me-0 md:-mb-2.5 shrink-0" />
</div>
{/* Tear-off Stub Portion */}
<div className="w-full md:w-48 bg-secondary/50 p-6 flex flex-col justify-between items-center text-center">
<div className="w-full">
<span className="font-mono text-[10px] uppercase tracking-[0.2em] text-muted-foreground">
STUB
</span>
<div className="mt-1 font-mono text-xs font-semibold text-foreground truncate">
{eventName}
</div>
<div className="mt-2 text-xs font-mono text-muted-foreground">
R: {seatInfo.row} · S: {seatInfo.seat}
</div>
</div>
{/* Status Stamp */}
<div className="my-4">
<span
className={cn(
"inline-block rotate-[-6deg] rounded-sm border px-2 py-0.5 font-mono text-[11px] font-bold uppercase tracking-widest",
status === "admitted" && "border-primary text-primary bg-primary/10",
status === "valid" && "border-accent text-accent bg-accent/10",
status === "void" && "border-destructive text-destructive bg-destructive/10"
)}
>
{status}
</span>
</div>
<div className="font-mono text-[9px] text-muted-foreground tracking-widest uppercase">
{barcodeValue}
</div>
</div>
</div>
);
}
Props
| Prop | Type | Description |
|---|---|---|
| serial? | string | |
| eventName? | string | |
| admitCount? | string | |
| seatInfo? | { row?: string | |
| seat? | string | |
| section? | string | |
| gate? | string } | |
| date? | string | |
| time? | string | |
| price? | string | |
| barcodeValue? | string | |
| status? | "admitted" | "valid" | "void" | |
| className? | string |