Data

Ticket

An event ticket with a tear line and stub: event, date, venue, section, row and seat, the holder, a code or a QR as children.

#document#card#schedule#print#no-js

Demo

Preview

Evening talk

Ada Lovelace Day

19:30Royal Institution, London
Section
Stalls
Row
C
Seat
12
Admit Grace Hopper£24.00No. 0931
Ada Lovelace DaySection Stalls · Row C · Seat 12
ALD-2026-0931

General admission

Quillo Conf

Porto
Gate
B
Admit Ada Lovelace
Quillo ConfGate B

Get it

It needs theme.qwe, as every component does; or take the whole kit, quillo-ui.qwe. Each component brings its own styles to the pages that show it.

$ curl -O https://quillolang.org/components/ui/theme.qwe$ curl -O https://quillolang.org/components/ui/ticket.qwe
main.qwe
import ui/theme.qwe use theme_cssuse ui/ticket.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>

Example

The code of the preview above.

demos/ticket.qwe
view TicketDemo() =    <div.demo-stack>        <Ticket id="ticket-demo-ada" kind="Evening talk" event="Ada Lovelace Day" date="2026-10-13" time="19:30" venue="Royal Institution, London"                section="Stalls" row="C" seat="12" holder="Grace Hopper" price="£24.00" number="0931" code="ALD-2026-0931"                src="https://picsum.photos/seed/hall/800/300"/>        <Ticket id="ticket-demo-ga" kind="General admission" event="Quillo Conf" date="2026-11-20" venue="Porto" gate="B" holder="Ada Lovelace" tone="success">            <svg width="72" height="72" viewBox="0 0 8 8" shape-rendering="crispEdges" aria-label="A code" role="img">                <path fill="currentColor" d="M0 0h3v3H0zM5 0h3v3H5zM0 5h3v3H0zM4 1h1v1H4zM1 1h1v1H1zM6 1h1v1H6zM1 6h1v1H1zM4 4h1v1H4zM6 5h2v1H6zM5 6h1v2H5zM7 7h1v1H7z"/>            </svg>        </Ticket>    </div>

Source

ui/ticket.qwe
// Ticket: an event ticket: the event, when and where, the section, row and seat,// whose it is, and a code, with a stub along a tear line for the door. The code// can be text, or a QrCode or Barcode as children.////   <Ticket event="Ada Lovelace Day" date="2026-10-13" time="19:30" venue="Royal Institution, London"//           section="Stalls" row="C" seat="12" holder="Grace Hopper" price="£24.00" code="ALD-2026-0931"/>//   <Ticket {...t}><QrCode text={t.code} size={96}/></Ticket>//// event: its name; kind: "General admission", "VIP" (a label over it). date: an ISO// date, shown as "Mon 13 Oct 2026"; time: as it should read ("19:30"); venue: where.// section, row, seat: the place, each left out when it is not numbered (gate and// door too). holder: whose ticket; price: what it cost; number: the ticket's number.// code: the code written on the stub (under children, when given). src: a picture// of the event behind the top. tone: "accent" (default), "success", "warning",// "danger" or "info" for its colour. id: its id. Each one is an <article>.import ui/theme.qwe use ui_clslet ticket_css = css`.ui-ticket { --t: var(--ui-accent); --tf: var(--ui-accent-fg); position: relative; display: flex; width: 100%; max-width: 560px; min-width: 0; margin: 0;  border-radius: var(--ui-radius); background: var(--ui-surface); color: var(--ui-fg); font: 14px/1.4 var(--ui-font); box-shadow: var(--ui-shadow);  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .04)); }.ui-ticket-success { --t: var(--ui-success); --tf: #fff; }.ui-ticket-warning { --t: var(--ui-warning); --tf: #fff; }.ui-ticket-danger { --t: var(--ui-danger); --tf: #fff; }.ui-ticket-info { --t: var(--ui-info); --tf: #fff; }.ui-ticket-main { flex: 1; min-width: 0; display: grid; gap: 14px; padding: 18px 20px; border-radius: var(--ui-radius) 0 0 var(--ui-radius); overflow: hidden; }.ui-ticket-top { position: relative; margin: -18px -20px 0; padding: 18px 20px 14px; background: var(--t); color: var(--tf); }.ui-ticket-top img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: .35; }.ui-ticket-top > * { position: relative; }.ui-ticket-kind { margin: 0; font-size: 11px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; opacity: .85; }.ui-ticket-event { margin: 0; font-size: 20px; font-weight: 700; line-height: 1.2; letter-spacing: -.01em; }.ui-ticket-when { display: flex; flex-wrap: wrap; gap: 4px 14px; color: var(--ui-muted); font-size: 13px; }.ui-ticket-when b { color: var(--ui-fg); font-weight: 600; }.ui-ticket-place { display: flex; flex-wrap: wrap; gap: 10px 22px; margin: 0; }.ui-ticket-place div { display: grid; gap: 1px; }.ui-ticket-place dt { color: var(--ui-muted); font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; }.ui-ticket-place dd { margin: 0; font-size: 18px; font-weight: 700; font-variant-numeric: tabular-nums; }.ui-ticket-foot { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 4px 14px; color: var(--ui-muted); font-size: 13px; }.ui-ticket-foot b { color: var(--ui-fg); font-weight: 500; }.ui-ticket-stub { position: relative; flex: 0 0 150px; display: grid; align-content: center; justify-items: center; gap: 8px; padding: 18px 14px;  border-left: 2px dashed var(--ui-strong); border-radius: 0 var(--ui-radius) var(--ui-radius) 0; text-align: center; }.ui-ticket-stub::before, .ui-ticket-stub::after { content: ""; position: absolute; left: -11px; width: 20px; height: 20px; border-radius: 50%; background: var(--ui-bg); }.ui-ticket-stub::before { top: -10px; }.ui-ticket-stub::after { bottom: -10px; }.ui-ticket-stub-event { font-size: 12px; font-weight: 600; overflow-wrap: anywhere; }.ui-ticket-stub-seat { color: var(--ui-muted); font-size: 12px; }.ui-ticket-code { font: 12px/1.3 var(--ui-mono); letter-spacing: .06em; overflow-wrap: anywhere; }.ui-ticket-slot:empty { display: none; }@media (max-width: 440px) {  .ui-ticket { flex-direction: column; }  .ui-ticket-main { border-radius: var(--ui-radius) var(--ui-radius) 0 0; }  .ui-ticket-stub { flex: none; border-left: 0; border-top: 2px dashed var(--ui-strong); border-radius: 0 0 var(--ui-radius) var(--ui-radius); }  .ui-ticket-stub::before, .ui-ticket-stub::after { top: -11px; bottom: auto; }  .ui-ticket-stub::before { left: -10px; }  .ui-ticket-stub::after { left: auto; right: -10px; }}@media print { .ui-ticket { box-shadow: none; filter: none; border: 1px solid #000; } .ui-ticket-top { -webkit-print-color-adjust: exact; print-color-adjust: exact; } }`let ticket_days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]let ticket_months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]// An ISO date as "Mon 13 Oct 2026"; other text as it is.fn ticket_date(d) -> str {    let s = slice(str(d), 0, 10)    if !date.valid(s) { return str(d) }    let p = date.parts(s)    `${ticket_days[p.weekday - 1]} ${p.day} ${ticket_months[p.month - 1]} ${p.year}`}view Ticket(event: str, kind: str? = null, date = null, time: str? = null, venue: str? = null, section: str? = null, row: str? = null,            seat: str? = null, gate: str? = null, door: str? = null, holder: str? = null, price: str? = null, number: str? = null,            code: str? = null, src: str? = null, tone: str = "accent", id: str? = null, class: str? = null, children) {    style global ticket_css    let places = [["Section", section], ["Row", row], ["Seat", seat], ["Gate", gate], ["Door", door]] | filter((p) => p[1] != null)    <article class={ui_cls(["ui-ticket", tone != "accent" && `ui-ticket-${tone}`, class])} id={id} aria-label={`Ticket: ${event}`}>        <div.ui-ticket-main>            <div.ui-ticket-top>                {src != null && <img src={src} alt=""/>}                {kind != null && <p.ui-ticket-kind>{kind}</p>}                <h3.ui-ticket-event>{event}</h3>            </div>            {(date != null || time != null || venue != null) && <div.ui-ticket-when>                {date != null && <span><b><time datetime={str(date)}>{ticket_date(date)}</time></b></span>}                {time != null && <span><b>{time}</b></span>}                {venue != null && <span>{venue}</span>}            </div>}            {len(places) > 0 && <dl.ui-ticket-place>                {for p in places => <div key={p[0]}><dt>{p[0]}</dt><dd>{p[1]}</dd></div>}            </dl>}            {(holder != null || price != null || number != null) && <div.ui-ticket-foot>                {holder != null && <span>Admit <b>{holder}</b></span>}                {price != null && <span>{price}</span>}                {number != null && <span>No. <b>{number}</b></span>}            </div>}        </div>        <div.ui-ticket-stub aria-label="Stub">            <span.ui-ticket-stub-event>{event}</span>            {len(places) > 0 && <span.ui-ticket-stub-seat>{join(places | map((p) => `${p[0]} ${p[1]}`), " · ")}</span>}            <div.ui-ticket-slot>{children}</div>            {code != null && <span.ui-ticket-code>{code}</span>}        </div>    </article>}
Thread
67Useful? Like it, or add to its thread below.

Thread 0 posts

On Ticket: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.