This tutorial builds an interactive seating chart in React with the
@seatlayer/react npm package: a live seat map with selection, temporary holds,
and a checkout handoff to your own backend. It uses the released SeatPicker
component, so the map, selection tray, hold countdown, and mobile layout come
with it — you write the parts that belong to your product.
Test mode is free with no time limit and no card, so you can complete every step below before a live account exists. See SeatLayer pricing for what happens after that, or the seat map SDK and API overview for how the pieces fit together.
1. Install the package
npm i @seatlayer/react@^0.64.0yarn add @seatlayer/react@^0.64.0pnpm add @seatlayer/react@^0.64.0bun add @seatlayer/react@^0.64.0For script-tag, browser ESM, plain JavaScript, Vue, and Angular routes, see the install options for all frameworks.
2. Render the seating chart
The React wrapper exports SeatPicker. Give it an event key and an explicit
size — the SDK is container-responsive, so its mount element needs a definite
width and height.
import { SeatPicker } from "@seatlayer/react";
export function Checkout() {
return (
<SeatPicker
event="ev_9f3a"
style={{ width: "100%", height: 640 }}
onCheckout={(_, __, handoff) => {
beginCheckout(handoff.holdId);
}}
/>
);
}3. Authorize the browser
buyerAccessTokenProvider is called with a reason and returns a token and
expiry from your own authenticated backend. Keep the function outside the
component (or in a useCallback) so it is not recreated on every render.
import { SeatPicker } from "@seatlayer/react";
async function getSeatLayerBuyerAccess({ reason }) {
const response = await fetch("/api/seatlayer/buyer-access", {
method: "POST",
credentials: "same-origin",
cache: "no-store",
headers: { "content-type": "application/json" },
body: JSON.stringify({ reason }),
});
if (!response.ok) throw new Error("Unable to open seat selection");
return response.json();
}
export function Checkout() {
return (
<SeatPicker
event="ev_9f3a"
style={{ width: "100%", height: 640 }}
buyerAccessTokenProvider={getSeatLayerBuyerAccess}
onCheckout={(_hold, _seats, handoff) => {
startCheckout({ holdId: handoff.holdId });
}}
/>
);
}The bse_… token stays in memory. No sk_… credential belongs in a client
bundle.
4. React to selection and holds
The component takes the same options and callbacks as the SeatPicker reference, passed as props. Two are useful almost immediately:
onSelectionChange—(seats) => void, fires whenever the selection changes.onHoldChange—(hold, seats, handoff) => void, fires when a hold is created, restored, extended, partially released, or released.
const [seats, setSeats] = useState([]);
return (
<SeatPicker
event="ev_9f3a"
style={{ width: "100%", height: 640 }}
buyerAccessTokenProvider={getSeatLayerBuyerAccess}
onSelectionChange={setSeats}
onError={reportPickerError}
onCheckout={(_hold, _seats, handoff) => {
startCheckout({ holdId: handoff.holdId });
}}
/>
);SeatPicker already renders its own selection tray and hold countdown, so treat
this state as context for the rest of your page rather than a cart you have to
build.
5. Hand off to your checkout
A hold temporarily protects inventory while a buyer completes checkout. It is not a sale. The Buyer SDK creates the hold; your server inspects and books it.
The third onCheckout argument is the handoff:
interface CheckoutHandoff {
holdId: string;
expiresAt: number;
currency: string;
lineItems: CheckoutLineItem[];
total: number;
}Hand off only holdId
Your checkout route receives the hold identity and your own cart context, never a secret key or trusted price.
Build the trusted order on your server
It inspects the active hold, calculates the charge from its returned items, and runs your payment workflow.
Start a visible timer from server time
Count down from server expiresAt, not a locally invented duration.
The browser handoff is excellent display context, but payment still uses a fresh server-side inspection. The complete flow, including release and restore, is in holds and checkout handoff.
6. Optional: go headless with SeatingChart
@seatlayer/react also exports SeatingChart, the headless seating canvas
without SeatLayer’s cart/tray chrome. Reach for it only when your application
owns totals, tier/GA controls, the checkout button, countdown, and buyer
messages.
import { SeatingChart } from "@seatlayer/js";
const chart = new SeatingChart({
container: "#chart",
event: "ev_9f3a",
onSelectionChange: (seats) => {
updateYourSelectionUI(seats);
},
});
await chart.render();Choose SeatPicker unless your application has a clear reason to own selection
controls, confirmation, hold timing, pricing presentation, and mobile behavior.
Full options are in the
SeatingChart headless reference.
If you are weighing that against building the map yourself, the JavaScript seating chart guide walks through what a hand-built chart still leaves you owning.
Before you ship
- The package loads without browser errors.
- The mount container has an explicit usable size.
- A test event renders.
- Selection changes appear immediately.
- Checkout produces a
holdId. - No
sk_…credential exists in the client bundle. - Platform embeds use
buyerAccessTokenProvider; thebse_…token stays in memory. - Narrow mobile and keyboard behavior are usable.
Questions
Which React seating chart library should I use?
It depends on how much of the buyer experience you want to own. SeatPicker
gives you the complete flow — map, confirmation, pricing, selection tray, holds,
expiry, success state, mobile layout, and optional 3D — and is the fastest
production route. SeatingChart gives you only the live map canvas, and your
product builds the cart, CTA, timer, and states around it. Building on a generic
canvas or charting library instead means you also own venue geometry, live
inventory, hold expiry, and concurrency, which is the part that is hard to keep
correct.
Is there a React seat picker on npm?
Yes — @seatlayer/react, pinned in this tutorial at ^0.64.0. It provides
native SeatPicker and SeatingChart components, and re-exports the
framework-agnostic SeatPickerWidget modal and attachPickerFrame helper from
@seatlayer/js.
Is there a seats.io alternative for React?
SeatLayer publishes a native React SDK for reserved seating, covering the complete picker and the headless chart on the same event and live inventory model. For a feature-by-feature view, read the seats.io alternative page.
Continue to the Quickstart, or learn the core hold and booking model.