Elements
The Ticketlayer Elements: web components that list events, sell tickets and show orders on any page, plus the theme tokens they read.
Elements are web components (custom HTML tags prefixed tl-) that list events,
take a customer through ticket selection, cart and checkout, and show the
tickets they bought. They work in plain HTML, in Webflow or any site builder
that lets you add a script tag, and in React through the generated wrappers in
@ticketlayer/elements-react.
Every element binds to the Live client the page publishes on
window.Ticketlayer. Elements take no API key of their own: create the client
once (the CDN loader does this from its data-* attributes, or call
createLiveClient() from @ticketlayer/live) and the elements find it.
Get them onto the page#
CDN, no build step. One script tag loads the Live SDK, the Elements bundle and the hosted checkout modal. The tags below then just work.
<script src="https://cdn.ticketlayer.com/v1/ticketlayer.js"
data-publishable-key="tlpk_..."
data-api-url="live.ticketlayer.com"
data-checkout-base="checkout.ticketlayer.com"></script>
<tl-event-list columns="3"></tl-event-list>See the HTML quickstart for the attributes each environment needs today.
npm, for React and bundlers.
npm install @ticketlayer/live @ticketlayer/elements @ticketlayer/elements-reactimport { createLiveClient } from '@ticketlayer/live';
import { defineCustomElements, TlEventList } from '@ticketlayer/elements-react';
defineCustomElements(); // once, after hydration
await createLiveClient({ baseUrl: 'live.ticketlayer.com', publishableKey: 'tlpk_...' });
<TlEventList columns={3} onTlEventClick={(e) => console.log(e.detail.eventId)} />:::note Package status
@ticketlayer/live, @ticketlayer/elements and @ticketlayer/elements-react
are built in their repositories but are not on the public npm registry yet;
they publish once their release workflows run. Until then use the CDN build,
which is served at cdn.ticketlayer.com. See the
Vite quickstart for the workaround in the meantime.
:::
Elements#
Discovery#
List and present events.
| Element | React | What it does |
|---|---|---|
<tl-event-card> | TlEventCard | One event as a card: its image, name, next date, venue, what a ticket costs with fees, and how it is selling. |
<tl-event-list> | TlEventList | What the channel is selling, as a grid of event cards, optionally narrowed to one category. |
<tl-occurrence-selector> | TlOccurrenceSelector | A smart occurrence selector component that fetches and displays event occurrences from the Ticketlayer API. |
Purchase#
Choose a date, pick tickets, open the buy flow.
| Element | React | What it does |
|---|---|---|
<tl-best-available> | TlBestAvailable | The best seats for a party: a few options that differ (the best, a cheaper one, one closer or further back), each with the view from it, the row and seats, why it was chosen and the price. |
<tl-buy-modal> | TlBuyModal | The buy-tickets modal: a date, then tickets, then payment, under a header carrying the channel's and the event's identity, beside a basket showing what the buyer is paying for. |
<tl-buy-tickets-button> | TlBuyTicketsButton | A buy-tickets button in one of four sale states, which opens the purchase modal. |
<tl-buy-tickets-wrapper> | TlBuyTicketsWrapper | Wrap any content and open the purchase modal when it is activated. |
<tl-gift-card-shop> | TlGiftCardShop | Buy a gift card: choose the card, an amount it comes in, email or post (post only with a posted order), the recipient and a message, and add it to the basket. |
<tl-map-key> | TlMapKey | The seat map's key: a minimap of the whole venue with the part the map shows outlined (choose a section to go there), and the price bands, each category's colour and lowest price, with the seat states |
<tl-price-picker> | TlPricePicker | The ticket type of a held seat: Adult, Child, Concession and the rest of its category's types, as a dropdown or a segmented control, for one seat or every seat held for the occurrence. |
<tl-promo-code> | TlPromoCode | Apply a code to the current cart: what it unlocks, discounts or waives is that cart's and its order's. |
<tl-quantity-picker> | TlQuantityPicker | How many tickets: square buttons 1 to 5 and a 6+ dropdown up to the channel's limit, or a keypad for staff. |
<tl-seat-card> | TlSeatCard | One seat as a card: the view from it when there are views, the row and number, the section, the price, whether it is free or held, and for a held seat its ticket type to change. |
<tl-seat-explorer> | TlSeatExplorer | The seat map: the venue's sections, flown into one at a time, and its seats in their categories' colours. |
<tl-seat-preferences> | TlSeatPreferences | What a party prefers beyond how many: a price per ticket, an area, an aisle seat, wheelchair spaces and how together. |
<tl-seat-view> | TlSeatView | The view from one seat, or from a block of seats, in a box a little smaller than what it sits over, dimming it: the rendered still and a 360 look around its row where the venue has them, else the near |
<tl-ticket-selector> | TlTicketSelector | Pick quantities of the ticket types on sale for one occurrence, priced with every fee in them, and add them to the cart. |
Cart#
Show and edit what the customer is about to buy.
| Element | React | What it does |
|---|---|---|
<tl-cart> | TlCart | The buyer's cart: its lines, the money rows the surface reported and a checkout button. |
<tl-cart-badge> | TlCartBadge | A cart icon carrying the number of items in the cart, kept current from the cart bus. |
<tl-cart-drawer> | TlCartDrawer | A slide-in panel holding the cart, opened by the cart intent on the client bus. |
Checkout#
Hand off to the hosted checkout and confirm the order.
| Element | React | What it does |
|---|---|---|
<tl-checkout-credit> | TlCheckoutCredit | The checkout's gift cards and credit: apply the signed-in buyer's account credit, or a gift card by its code, see what each covers, and remove either before paying. |
<tl-checkout-holders> | TlCheckoutHolders | The checkout's "Who is this for?" section: a name for each guest, vehicle or group the cart makes, and who each add-on goes to, "one each" when that is automatic. |
<tl-checkout-summary> | TlCheckoutSummary | The checkout's order summary, priced from the cart's quote: the tickets with the fees included in them, each separate fee, any discount and the total checkout charges. |
<tl-checkout-wrapper> | TlCheckoutWrapper | Wrap any content and open the checkout modal when it is activated. |
<tl-delivery-picker> | TlDeliveryPicker | The checkout's Delivery section: how the tickets reach the buyer, each method with what it adds, and the reason beside one that cannot be chosen. |
<tl-order-confirmation> | TlOrderConfirmation | The thank-you block: order reference, email, event and date, the ticket lines, the money rows and the tickets. |
<tl-payment-picker> | TlPaymentPicker | The checkout's Payment section: the ways this order can be paid, each with any surcharge it adds, and the reason beside one that cannot be chosen. |
Tickets#
Render issued tickets with QR codes and PDF downloads.
| Element | React | What it does |
|---|---|---|
<tl-booking-pass> | TlBookingPass | The booking pass: one barcode for the whole order, listing everyone it covers until each has their own pass or wristband. |
<tl-holder-pass> | TlHolderPass | A named guest's own page, from the link the booker sent: their ticket and extras, their name under the event's rules, and their own pass to download. |
<tl-order-tickets> | TlOrderTickets | Every ticket in an order as a scannable card, waiting out issuance rather than reporting an empty order as empty. |
<tl-ticket> | TlTicket | A single issued ticket: a scannable QR, its name, seat and holder, and a PDF download. |
<tl-wristband-activate> | TlWristbandActivate | Activate a wristband that came in the post by tapping it on the phone (Web NFC where the browser has it); where it cannot, explains the desk at the event instead. |
Account#
Sign in with a magic link and show past orders.
| Element | React | What it does |
|---|---|---|
<tl-booking-holders> | TlBookingHolders | Manage my booking, people first: each holder with their ticket and add-ons, to name or rename, move an add-on to someone else, place add-ons nobody has yet, and activate a posted wristband. |
<tl-gift-card-balance> | TlGiftCardBalance | Check what is on a gift card by its code: the amount, until when, and whether it can be used. |
<tl-login> | TlLogin | Magic-link sign-in: an email in, a link or a six-digit code back, and a session. |
<tl-my-credit> | TlMyCredit | Your credit: the signed-in buyer's account credit with this organisation, each balance with its expiry and whether it is on hold, and its activity (what was put on it and spent, when, and on which ord |
<tl-my-orders> | TlMyOrders | The signed-in customer's orders: event, date, ticket count, total and status, each row expanding to its tickets. |
<tl-refund-request> | TlRefundRequest | Ask for a refund on an order, with a reason and where the money should go: back the way it was paid, or as account credit. |
Other#
| Element | React | What it does |
|---|---|---|
<tl-concierge> | TlConcierge | Concierge: search the help articles, ask the AI when the channel has it on, see my orders after a code typed into the widget, or contact the organiser. |
<tl-concierge-slot> | TlConciergeSlot | The "Need help?" another element hosts: renders nothing unless the channel has Concierge on for that placement, then a help field that opens tl-concierge inline with the host's context and what was ty |
Events#
Every element emits CustomEvents whose names start with tl and whose
payload is on event.detail. In HTML:
<tl-event-list></tl-event-list>
<script>
document.querySelector('tl-event-list').addEventListener('tlEventClick', (e) => {
location.href = '/events/' + e.detail.eventId;
});
</script>In React each event is a prop named onTl...:
<TlEventList onTlEventClick={(e) => ...} />.
Theming#
Elements read CSS custom properties prefixed --tl-. The Live SDK injects the
values of the channel's theme (configured in Backstage) when
applyTheme is on, which it is by default; set any token yourself on
:root or on a wrapper to override. The defaults below come from the
Elements global stylesheet and apply when nothing else sets the token.
Colour#
Palette.
| Token | Default |
|---|---|
--tl-primary | #4f46e5 |
--tl-color-primary | var(--tl-primary) |
--tl-primary-foreground | #ffffff |
--tl-color-primary-foreground | var(--tl-primary-foreground) |
--tl-secondary | #f3f4f6 |
--tl-color-secondary | var(--tl-secondary) |
--tl-secondary-foreground | #111827 |
--tl-color-secondary-foreground | var(--tl-secondary-foreground) |
--tl-accent | #ec4899 |
--tl-color-accent | var(--tl-accent) |
--tl-accent-foreground | #111827 |
--tl-color-accent-foreground | var(--tl-accent-foreground) |
--tl-background | #ffffff |
--tl-color-background | var(--tl-background) |
--tl-foreground | #111827 |
--tl-color-foreground | var(--tl-foreground) |
--tl-card | var(--tl-background) |
--tl-color-card | var(--tl-card) |
--tl-muted | #f9fafb |
--tl-color-muted | var(--tl-muted) |
--tl-muted-foreground | #6b7280 |
--tl-color-muted-foreground | var(--tl-muted-foreground) |
--tl-border | #e5e7eb |
--tl-color-border | var(--tl-border) |
--tl-border-hover | color-mix(in srgb, var(--tl-foreground) 35%, var(--tl-border)) |
--tl-color-border-hover | var(--tl-border-hover) |
--tl-input | #e5e7eb |
--tl-color-input | var(--tl-input) |
--tl-ring | #4f46e5 |
--tl-color-ring | var(--tl-ring) |
--tl-success | #10b981 |
--tl-color-success | var(--tl-success) |
--tl-success-foreground | #111827 |
--tl-color-success-foreground | var(--tl-success-foreground) |
--tl-warning | #f59e0b |
--tl-color-warning | var(--tl-warning) |
--tl-warning-foreground | #111827 |
--tl-color-warning-foreground | var(--tl-warning-foreground) |
--tl-warning-bg | color-mix(in srgb, var(--tl-warning) 15%, var(--tl-background)) |
--tl-color-warning-bg | var(--tl-warning-bg) |
--tl-error | #dc2626 |
--tl-color-error | var(--tl-error) |
--tl-destructive | var(--tl-error) |
--tl-color-destructive | var(--tl-error) |
--tl-error-foreground | #ffffff |
--tl-color-error-foreground | var(--tl-error-foreground) |
--tl-destructive-foreground | var(--tl-error-foreground) |
--tl-color-destructive-foreground | var(--tl-error-foreground) |
--tl-error-bg | color-mix(in srgb, var(--tl-error) 12%, var(--tl-background)) |
--tl-color-error-bg | var(--tl-error-bg) |
--tl-destructive-bg | var(--tl-error-bg) |
--tl-color-destructive-bg | var(--tl-error-bg) |
--tl-info | #3b82f6 |
--tl-color-info | var(--tl-info) |
--tl-info-foreground | #ffffff |
--tl-color-info-foreground | var(--tl-info-foreground) |
--tl-info-bg | color-mix(in srgb, var(--tl-info) 14%, var(--tl-background)) |
--tl-color-info-bg | var(--tl-info-bg) |
--tl-overlay | color-mix(in srgb, color-mix(in srgb, var(--tl-background) 22%, #000000) 55%, transparent) |
Type#
Font stacks, the base size and ratio, and the type scale derived from them.
| Token | Default |
|---|---|
--tl-font-family | system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif |
--tl-font-family-heading | var(--tl-font-family) |
--tl-font-weight-heading | 600 |
--tl-font-family-mono | ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace |
--tl-font-size-base | 16px |
--tl-base-size | var(--tl-font-size-base) |
--tl-font-scale | 1.25 |
--tl-font-size-2xs | calc(var(--tl-font-size-base) * pow(var(--tl-font-scale), -1.5)) |
--tl-font-size-xs | calc(var(--tl-font-size-base) * pow(var(--tl-font-scale), -1)) |
--tl-font-size-sm | calc(var(--tl-font-size-base) * pow(var(--tl-font-scale), -0.5)) |
--tl-font-size-md | var(--tl-font-size-base) |
--tl-font-size-lg | calc(var(--tl-font-size-base) * pow(var(--tl-font-scale), 0.5)) |
--tl-font-size-xl | calc(var(--tl-font-size-base) * pow(var(--tl-font-scale), 1)) |
--tl-font-size-2xl | calc(var(--tl-font-size-base) * pow(var(--tl-font-scale), 2)) |
--tl-font-size-3xl | calc(var(--tl-font-size-base) * pow(var(--tl-font-scale), 3)) |
Radius#
Corner radii.
| Token | Default |
|---|---|
--tl-radius-none | 0px |
--tl-radius-sm | 0.25rem |
--tl-radius-md | 0.5rem |
--tl-radius | var(--tl-radius-md) |
--tl-radius-lg | 0.75rem |
--tl-radius-full | 9999px |
Spacing#
The spacing step scale.
| Token | Default |
|---|---|
--tl-spacing-1 | 0.25rem |
--tl-spacing-2 | 0.5rem |
--tl-spacing-3 | 0.75rem |
--tl-spacing-4 | 1rem |
--tl-spacing-5 | 1.25rem |
--tl-spacing-6 | 1.5rem |
--tl-spacing-8 | 2rem |
Motion#
Durations and easings.
| Token | Default |
|---|---|
--tl-duration-fast | 120ms |
--tl-duration-normal | 200ms |
--tl-duration-slow | 320ms |
--tl-easing-standard | cubic-bezier(0.2, 0, 0, 1) |
--tl-easing-emphasised | cubic-bezier(0.3, 0, 0, 1) |
Seat map#
The seat map: the map itself (map-*: background, plates, sections, labels, pins), the stage (stage-*) and the seats (seat-*: each state, the selected seat on the brand colour, the hover ring and the sizes they are drawn at).
| Token | Default |
|---|---|
--tl-map-background | #f4f4f5 |
--tl-map-plate | #ffffff |
--tl-map-section | #ececef |
--tl-map-section-outline | #a1a1aa |
--tl-stage-fill | #e4e4e7 |
--tl-stage-edge | #d4d4d8 |
--tl-stage-label | #52525b |
--tl-map-label | #52525b |
--tl-map-pillar | #a1a1aa |
--tl-map-pillar-edge | #71717a |
--tl-map-aisle | #fafafa |
--tl-map-aisle-line | #a1a1aa |
--tl-seat-available | var(--tl-primary) |
--tl-seat-unavailable | #d4d4d8 |
--tl-seat-killed | #e4e4e7 |
--tl-seat-held | #d97706 |
--tl-seat-comp | #0d9488 |
--tl-seat-allocated | #a21caf |
--tl-seat-reserved | #a1a1aa |
--tl-seat-selected | var(--tl-primary) |
--tl-seat-selected-mark | var(--tl-primary-foreground) |
--tl-seat-selected-ring | var(--tl-foreground) |
--tl-seat-hover-ring | var(--tl-foreground) |
--tl-map-pin | #ffffff |
--tl-map-pin-border | #e4e4e7 |
--tl-map-pin-text | var(--tl-foreground) |
--tl-map-pin-active | var(--tl-foreground) |
--tl-map-pin-active-text | var(--tl-background) |
--tl-map-pin-shadow | #09090b2e |
--tl-seat-scale | 0.4 |
--tl-seat-unavailable-scale | 0.6 |
--tl-seat-min-radius | 1.2px |
--tl-seat-hit-radius | 3px |
--tl-seat-hover-ring-width | 1.5px |
--tl-stage-radius | 9px |
--tl-map-pin-height | 28px |
--tl-map-label-size | var(--tl-font-size-xs) |
--tl-map-pin-font-size | var(--tl-font-size-xs) |
:root {
--tl-primary: #0f766e;
--tl-primary-foreground: #ffffff;
--tl-radius-md: 0.25rem;
--tl-font-family: 'Inter', system-ui, sans-serif;
}Elements render in shadow DOM, so ordinary CSS selectors from the page do not reach inside them; the tokens are the styling contract.