SeatLayer React Native 0.4.0 ships a complete native buyer picker for Expo and
React Native Community CLI applications. The package includes the ready-made
flow, a controlled modal, themes and locale strings, 62 style slots, 27
complete-part builders, public components for a host-owned layout, and the
preserved low-level SeatLayerView API.
Install
npm install @seatlayer/react-native@0.4.0
npx expo install react-native-webviewnpm install @seatlayer/react-native@0.4.0 react-native-webview
npx pod-installReact Native autolinks react-native-webview on iOS and Android. SeatLayer
ships no additional native module, pod, or manual linking step.
On iOS, the seat-note and accessibility icons need a vector renderer. Add the
optional react-native-svg peer and register it once at start-up:
import Svg, { Circle, Path } from 'react-native-svg';
import { installSeatLayerPickerSvgIcons } from '@seatlayer/react-native';
installSeatLayerPickerSvgIcons({ Svg, Path, Circle });Without it, iOS keeps the words and drops the icon beside them. Give the picker a full-screen or otherwise bounded parent; the map cannot infer height from an unbounded layout.
Render the complete picker
Memoize the configuration with useMemo. A publishable key is appropriate
for Public inventory; private or audience-restricted inventory uses the
renewable provider shown below.
import React, { useMemo } from 'react';
import { View } from 'react-native';
import {
SeatLayerPicker,
type SeatLayerConfiguration,
type SeatLayerPickerCheckoutHandoff,
} from '@seatlayer/react-native';
export function TicketPickerScreen({ event }: { readonly event: string }) {
const configuration = useMemo<SeatLayerConfiguration>(
() => ({
event,
publicKey: '<YOUR_PUBLIC_KEY>',
currency: 'USD',
maxSelection: 8,
}),
[event],
);
const continueWithHandoff = async (
handoff: SeatLayerPickerCheckoutHandoff,
) => {
await checkoutBackend.begin({ holdId: handoff.holdId });
};
return (
<View style={{ flex: 1 }}>
<SeatLayerPicker
configuration={configuration}
themeMode="auto"
onCheckout={continueWithHandoff}
/>
</View>
);
}The default tree covers loading, live availability, price and accessibility filters, venue/floor/section navigation, confirmation and ticket tiers, GA and table quantities, a cart with one card per ticket, temporary holds, expiry recovery, 2D/3D and panorama chrome, and one typed checkout handoff.
Public and private inventory
For login-gated, presale, partner, channel, or other private inventory, omit
publicKey and provide renewable buyer access from your authenticated backend:
const configuration = useMemo<SeatLayerConfiguration>(
() => ({
event,
buyerAccessTokenProvider: ({ reason }) =>
buyerBackend.mintSeatLayerAccess(reason),
}),
[event],
);Mint the native buyer-access session through buyer access sessions, return only its short-lived token to the provider, and treat the SDK access context as opaque. Tokens stay in memory. Never put a SeatLayer secret key in JavaScript, the app bundle, a URL, a React key, an event payload, logs, or analytics.
Choose an integration level
| Level | Entry point | Your application owns |
|---|---|---|
| Complete screen | SeatLayerPicker |
Route, configuration, callbacks, checkout destination |
| Controlled presentation | SeatLayerPickerModal |
Visibility, barrier behavior, and dismissal |
| Branded flow | Picker + options, theme, strings, styles, builders | Brand and selected complete parts |
| Custom hierarchy | SeatLayerPickerScope + public components |
The complete React Native layout |
| Raw map | SeatLayerView + SeatLayerController |
Every buyer surface and hold transition |
All five paths use the same inventory source. The first four keep the native picker’s selection rules, hold ownership, lifecycle recovery, supported-feature checks, and checkout handoff.
Present it as a modal
<SeatLayerPickerModal
visible={isPickerOpen}
configuration={configuration}
onCheckout={continueWithHandoff}
onRequestClose={() => setPickerOpen(false)}
barrierDismissible
/>The modal uses the same scope and semantic Back ladder as the in-page picker; it does not create a second product surface.
Brand or replace individual parts
<SeatLayerPicker
configuration={configuration}
themeMode="dark"
locale="fr-FR"
options={{
layout: 'adaptive',
chrome: { priceLegend: false },
haptics: true,
languages: ['en-GB', 'fr-FR'],
}}
strings={{ holdAndCheckout: 'Continue' }}
styles={{
headerContainer: { backgroundColor: '#172033' },
continueButton: { backgroundColor: '#5B4B8A' },
}}
builders={{ header: ({ defaultChild }) => defaultChild }}
onCheckout={continueWithHandoff}
/>Use options for behavior and visibility, theme roles for coordinated native/map color, locale and strings for wording, style slots for aesthetic changes, and a builder when a complete part needs different structure. Builders receive the live scope and canonical child; they do not become inventory authority.
See every integration layer and public component.
Checkout and hold ownership
The picker selects and holds inventory. Your trusted backend inspects and books the hold after payment or order validation.
onCheckoutreceives one opaqueSeatLayerPickerCheckoutHandoff.- Send only
handoff.holdIdand your normal order context to the backend. - Inspect the hold and calculate payable totals from trusted server data.
- Charge through your payment provider.
- Reuse the same
bookingRefso retries are idempotent.
Ordinary picker state deliberately omits the hold ID. Before a successful handoff, the picker owns the hold and may release it on close. After your callback accepts the handoff, your product owns booking, rejection/release, or expiry. If the callback rejects, the SDK rejects that exact handoff and returns the buyer to a recoverable picker state.
Read holds and secure checkout before wiring payment.
Application and SDK ownership
| React Native components own | SeatLayer SDK owns |
|---|---|
| Header, price/floor/section navigation, accessibility filters, confirmation, quantities, cart, hold state, checkout, loading/errors, Test Mode, required attribution, Back and adaptive presentation | Seats, labels, geometry, hit testing, pan/pinch, camera, authored venue 3D, and panorama pixels |
| Safe areas, app lifecycle, native component layout, haptics, and accessibility semantics | Authoritative inventory state and supported map capabilities |
Changing native presentation does not create another map or discard camera, selection, or hold state.
Lifecycle and recovery
The ready picker handles foreground synchronization, availability refresh, hold-lapse recovery, viewport insets, and a deterministic Back ladder. Keep the picker mounted for the screen lifecycle and keep configuration identity unchanged.
- A resumed app reconciles the server hold instead of trusting a paused timer.
- Seats sold while the app was away are removed through authoritative unavailable-object state.
- Repeated checkout taps join one flight.
- A rejected checkout remains recoverable in the picker.
- Unmount permanently ends that picker session.
- Restore a host-owned hold only when your checkout promises restoration.
Raw-map applications must implement these host responsibilities themselves; see the raw-map reference.
Run the tagged example
git clone --branch v0.4.0 --depth 1 https://github.com/seatlayer/seatlayer-react-native.git
cd seatlayer-react-native
pnpm install
cd example
pnpm install
EXPO_PUBLIC_SEATLAYER_EVENT="<YOUR_EVENT_KEY>" \
EXPO_PUBLIC_SEATLAYER_PUBLIC_KEY="<YOUR_PUBLIC_KEY>" \
pnpm startThe Expo example mounts the ready-made picker and exercises the secure checkout handoff. Validate real inventory, lifecycle, safe areas, rotation, accessibility, 3D/panorama, and checkout on supported physical iOS and Android devices before rollout.
Product scope
React Native 0.4.0 accepts one published Event per picker. Native Performance
Group and Season configuration is not part of this release; use their browser
pickers until a native release documents those contracts.