Skip to content

Repository files navigation

SeatLayer React Native Seat Map SDK for Reserved Seating

CI npm React Native Expo TypeScript License: MIT

The official SeatLayer React Native SDK for adding an interactive seating chart and seat picker to iOS and Android ticketing apps. Render live seat availability, create temporary holds, find best-available seats, and hand secure booking to your trusted server through a typed TypeScript API.

@seatlayer/react-native on npm · React Native seat-map documentation · SeatLayer reserved-seating platform · Buyer seat-map demo (web) · SeatLayer iOS seat map SDK · SeatLayer Android seat map SDK · SeatLayer Flutter seat map SDK · SeatLayer AI Toolkit

Production SDK: Pin the documented 0.2.x release and validate your event, checkout handoff, lifecycle, and supported physical devices before rollout.

Install

Expo

npm install @seatlayer/react-native
npx expo install react-native-webview

React Native Community CLI

npm install @seatlayer/react-native react-native-webview
npx pod-install

React Native autolinks react-native-webview on Android and iOS. The package ships no custom native module of its own, so there is nothing else to link.

Peer requirements are react >= 18.2.0, react-native >= 0.72.0, and react-native-webview >= 13.0.0. TypeScript declarations are published with the package — dist/index.d.ts for ESM and dist/index.d.cts for CommonJS — so no @types/* package is needed.

Quick start

Give the map a definite height or a full-screen parent. Keep the configuration object stable so React rerenders do not reload the chart.

import React, { useEffect, useMemo } from 'react';
import { View } from 'react-native';
import {
  SeatLayerError,
  SeatLayerView,
  useSeatLayerController,
} from '@seatlayer/react-native';

export function SeatMapScreen({ event }: { readonly event: string }) {
  const controller = useSeatLayerController();
  const configuration = useMemo(
    () => ({
      event,
      publicKey: 'pk_test_your_key',
      currency: 'USD',
      maxSelection: 8,
    }),
    [event],
  );

  useEffect(
    () =>
      controller.on('selectionChanged', (seats) => {
        console.log('Selected seats', seats);
      }),
    [controller],
  );

  return (
    <View style={{ flex: 1 }}>
      <SeatLayerView
        style={{ flex: 1 }}
        controller={controller}
        configuration={configuration}
        onReady={(info) => {
          console.log(
            `SeatLayer ready: protocol=${info.protocolRevision} mode=${info.mode}`,
          );
        }}
        onLoadError={(error) => {
          console.error(error.code, error.message);
        }}
      />
    </View>
  );
}

Drive checkout-related actions through the controller:

try {
  const hold = await controller.bestAvailable(4);
  if (hold) {
    // Send only the hold id to your trusted backend.
    await beginCheckoutOnServer(hold.holdId);
  }
} catch (error) {
  if (error instanceof SeatLayerError) {
    showInventoryMessage(error.code, error.message);
  }
}

For private channel inventory, mint short-lived buyer sessions on your backend for the exact allowed origin https://cdn.seatlayer.io:

const configuration = useMemo(
  () => ({
    event,
    buyerAccessTokenProvider: (context) =>
      buyerBackend.mintSeatLayerAccess(context.reason),
  }),
  [event],
);

Native picker integration levels

The native picker uses one immutable latest snapshot as its seam. Choose the integration level that matches the amount of application UI you want to own; all three paths keep the same typed checkout handoff and capability-gated actions.

1. Ready-made picker

SeatLayerPicker fills its bounded parent with the adaptive SeatLayer venue map and native picker chrome.

import { SeatLayerPicker } from '@seatlayer/react-native';

<SeatLayerPicker
  configuration={configuration}
  themeMode="auto"
  onCheckout={continueWithHandoff}
/>

Use SeatLayerPickerModal for a controlled dialog or full-screen presentation. It uses the same scope, snapshot, and back ladder as the in-page picker.

import { SeatLayerPickerModal } from '@seatlayer/react-native';

<SeatLayerPickerModal
  visible={isPickerOpen}
  configuration={configuration}
  onCheckout={continueWithHandoff}
  onRequestClose={() => setPickerOpen(false)}
  barrierDismissible
/>

2. Customise the ready-made UI

Use typed options, theme roles, string overrides, visual style slots, and complete-part builders to change native chrome without changing picker state or actions.

<SeatLayerPicker
  configuration={configuration}
  themeMode="dark"
  options={{
    layout: 'adaptive',
    chrome: { priceLegend: false },
    haptics: true,
  }}
  strings={{ holdAndCheckout: 'Continue' }}
  styles={{
    headerContainer: { backgroundColor: '#172033' },
    continueButton: { backgroundColor: '#5B4B8A' },
  }}
  builders={{ header: ({ defaultChild }) => defaultChild }}
  onCheckout={continueWithHandoff}
/>

3. Compose a custom layout

SeatLayerPickerScope owns one command controller and one latest immutable snapshot. The standalone parts below read the same scoped theme, capabilities, presentation state, and actions.

import {
  SeatLayerCartSheet,
  SeatLayerDockBar,
  SeatLayerFloorStrip,
  SeatLayerPickerChart,
  SeatLayerPickerHeader,
  SeatLayerPickerScope,
  SeatLayerPriceLegend,
} from '@seatlayer/react-native';

<SeatLayerPickerScope configuration={configuration} themeMode="auto">
  <SeatLayerPickerHeader />
  <SeatLayerPriceLegend />
  <SeatLayerFloorStrip />
  <SeatLayerPickerChart style={{ flex: 1 }} />
  <SeatLayerDockBar />
  <SeatLayerCartSheet
    expanded={isCartExpanded}
    onExpandedChanged={setCartExpanded}
    onCheckout={continueWithHandoff}
  />
</SeatLayerPickerScope>

Call useSeatLayerPicker() inside the scope when your own component needs the latest snapshot, resolved theme, capability availability, presentation state, or scoped actions.

Run the example app

pnpm install
cd example && pnpm install && pnpm start

example/App.tsx is an Expo app with raw map, ready-made picker, modal, customised picker, and scoped custom-layout paths. Set EXPO_PUBLIC_SEATLAYER_EVENT and, for public startup, EXPO_PUBLIC_SEATLAYER_PUBLIC_KEY before starting it; when the event is absent, the example shows setup guidance and does not mount a picker. The browser-based buyer seat-map demo is a preview of the wider SeatLayer buyer experience, not a React Native app.

Security boundary

The React Native app selects and holds inventory. Your trusted backend inspects and books the hold after payment or order validation.

  • Never ship a SeatLayer secret key in JavaScript or the app bundle.
  • Send only the holdId and your normal checkout context to your backend.
  • Calculate the charge from server-inspected hold items, not device input.
  • Reuse your stable order id as the booking reference for safe booking retries.
  • Do not allow arbitrary navigation from the SDK renderer.

Continue with seat holds and secure server-side checkout before connecting payment and booking.

React Native renderer architecture

SeatLayerView is a React component that renders the SeatLayer venue map. It loads the immutable, version-pinned SeatLayer runtime and its lazy assets from the canonical CDN origin, which gives iOS and Android one canonical HTTPS origin for origin-bound buyer sessions. Register https://cdn.seatlayer.io on the publishable key used for public startup. For private inventory, omit publicKey and use buyerAccessTokenProvider; buyer access tokens stay in memory and are never placed in a page URL, a React key, or an event payload.

Application code never touches the renderer. It works through a typed TypeScript controller whose contract matches the Web, iOS, and Flutter SDKs:

  • range-negotiated protocol compatibility before the chart renders;
  • one response per command, matched by correlation id;
  • a 15-second command deadline, with late replies dropped rather than delivered;
  • monotonic event ordering per event name, so a stale envelope is discarded; and
  • forward-compatible unknown events and unknown payload fields.

See the bridge contract for the wire-level details.

Commands

hold · resumeHold · extendHold · release · releaseLabels · bestAvailable · holdGA · setSeatTier · getSelection · selectObjects · deselectObjects · clearSelection · selectCategories · deselectCategories · setSelectableObjects · setMaxSelection · getSelectionValidity · refreshAccess · getCurrentHold · getGAAreas · getFloors · setFloor · setColorblindSafe · setViewMode · getViewMode · zoomIn · zoomOut · zoomToFit · destroy

Every command returns a promise. Failures reject with SeatLayerError. Inventory outcomes such as sold_out, not_enough_together, expired holds, and hold conflicts remain distinct codes suitable for buyer-facing recovery.

Events

Subscribe with controller.on(name, listener). The returned function removes the listener.

useEffect(() => {
  const offHold = controller.on('holdChanged', persistOpenHold);
  const offExpired = controller.on('holdExpired', returnBuyerToSelection);
  const offError = controller.on('error', reportSeatLayerError);
  return () => {
    offHold();
    offExpired();
    offError();
  };
}, [controller]);

Events: ready · selectionChanged · holdChanged · holdRestored · holdExpired · selectionValidityChanged · selectionValid · selectionInvalid · selectionLimit · accessExpired · accessUnavailable · selectedObjectsUnavailable · error · hint · gaClick · seatHover · deckTap · checkout · unknownEvent

Unknown future events remain observable through unknownEvent; adding a bundle event does not crash an older app.

Layout and lifecycle

  • Use a fixed-height or full-screen parent; do not put the map inside a vertical ScrollView. The canvas owns pan and pinch for map navigation.
  • Keep configuration stable with useMemo.
  • Change reloadKey to deliberately rebuild the renderer and bridge.
  • useSeatLayerController disposes the controller automatically on unmount.
  • Persist an open holdId and call resumeHold after app restoration.

Frequently asked questions

How do I add a seat map to a React Native app?

Install @seatlayer/react-native alongside react-native-webview, create a controller with useSeatLayerController(), and render <SeatLayerView> with your event key in a full-screen or fixed-height parent. The quick start above is a complete interactive seating chart with live availability; the React Native seat-map documentation covers lifecycle, commands, and events in depth.

Is this a native seat map component?

SeatLayerView is a React Native component with a typed TypeScript controller and a SeatLayer venue-map renderer. The package contains no custom native module — no podspec, no Java, Kotlin, Swift, or Objective-C source — so application code works through TypeScript commands, payloads, errors, and events.

Does it work with Expo?

Yes. The only native dependency is react-native-webview, which Expo documents and includes in Expo Go, so npx expo install react-native-webview is enough for Expo Go on a supported Expo SDK. Development builds and bare React Native projects work the same way, and the repository's own example/ app is an Expo app that renders the SDK.

How do temporary seat holds work?

When a buyer selects seats, the SDK creates a temporary hold that reserves the inventory against concurrent buyers for a limited window. The hold expires automatically if checkout does not complete — the holdExpired event tells the app to return the buyer to the map — and extendHold and resumeHold cover longer checkouts and app restarts. This prevents double-selling without locking seats forever.

Can I use my own payment provider?

Yes. SeatLayer never processes payment inside the seat map. The app hands the holdId to your backend, and your backend charges through any payment provider you already use — Stripe, Adyen, Razorpay, or your own — before booking the hold through the server-side checkout flow.

Which React Native and React versions are supported?

The package declares peer dependencies of react >= 18.2.0, react-native >= 0.72.0, and react-native-webview >= 13.0.0, and it is developed and tested against React Native 0.86 and React 19. Both iOS and Android are supported; the SDK ships ESM, CommonJS, and TypeScript declaration outputs from one build.

Continue your React Native integration

SeatLayer SDK ecosystem

Surface Package or source
React Native @seatlayer/react-native (this package)
JavaScript @seatlayer/js
React @seatlayer/react
iOS seatlayer-ios
Flutter seatlayer
Android seatlayer-android
Server SDKs Node.js, Python, PHP, Ruby, .NET, Java, and Go

Development

pnpm install
pnpm validate

pnpm validate type-checks, runs the protocol tests, builds ESM, CommonJS, and type declarations, and validates the npm tarball with publint and @arethetypeswrong/cli. Production loads the exact hosted runtime; the package does not generate or ship an inline Web document.

License

MIT © SeatLayer

About

SeatLayer's official React Native seat map SDK — interactive reserved-seating charts with live availability, seat selection, holds, and a typed TypeScript API for iOS and Android ticketing apps.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages