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-card

Or install the full npm package:

npm install bigbullui
import { 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.tsx

Zero 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

PropTypeDescription
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