Skip to content

Native picker and custom layouts

Use the React Native 0.3.4 picker as a ready-made flow, customise any complete part, or compose a host-owned layout from public components.

Updated View as Markdown

React Native 0.3.4 ships the complete native picker on npm. It adds a ready-made screen, controlled modal, generated themes and locale strings, standalone scoped chrome, adaptive presentation, and capability-aware actions while preserving the raw-map API.

What is native

React Native components own the header, price/floor/section navigation, accessibility filters, confirmation, tier and quantity decisions, cart, hold status, checkout, loading, errors, and controls around immersive views. SeatLayer owns seat geometry, labels, map gestures, venue 3D, panorama, and authoritative inventory behavior behind the public SDK API.

That seam gives the host a real React Native hierarchy without duplicating the venue engine, inventory state, or hold contract.

Integration ladder

Level API What changes
Complete flow SeatLayerPicker Configuration and callbacks only
Controlled modal SeatLayerPickerModal Visibility and dismissal
Branded flow Theme, strings, options, styles, builders Expression or selected complete parts
Custom hierarchy SeatLayerPickerScope + public components Entire React Native layout
Raw map SeatLayerView + SeatLayerController Host owns every buyer state and transition

The first four levels retain one picker state, ordered inventory actions, supported-feature checks, hold ownership, lifecycle recovery, and the same typed checkout handoff.

Ready-made picker

<SeatLayerPicker
  configuration={{
    event: 'ev_your_event_key',
    publicKey: 'pk_test_your_public_key',
    currency: 'USD',
  }}
  themeMode="auto"
  onCheckout={(handoff) =>
    checkoutBackend.begin({ holdId: handoff.holdId })
  }
/>

Use SeatLayerPickerModal when the picker is controlled by a parent route or dialog. Both use the same adaptive compact/wide tree and semantic Back ladder.

Customize without forking

The layers have separate ownership:

Layer Use it for It must not change
options Behavior, adaptive layout, optional chrome, haptics, languages, display price formatter Inventory prices, state truth, safe areas
themeMode, themeOptions Semantic native and map color roles, typography, radii, logos Authoritative Event branding
locale, strings One of 37 generated dictionaries and exact host overrides Event data supplied by SeatLayer
styles 62 aesthetic slots for color, type, borders, radii, shadows, opacity SDK placement, viewport insets, 44-point minimum targets
builders Wrap or replace one of 25 complete parts Inventory state, actions, hold ownership
<SeatLayerPicker
  configuration={configuration}
  themeMode="dark"
  options={{
    layout: 'adaptive',
    chrome: { priceLegend: false },
    haptics: true,
    languages: ['en-GB', 'fr-FR'],
    pricing: {
      formatter: (amount, currency) =>
        new Intl.NumberFormat('fr-FR', {
          style: 'currency',
          currency,
        }).format(amount),
    },
  }}
  locale="fr-FR"
  strings={{ holdAndCheckout: 'Continue' }}
  styles={{
    headerContainer: { backgroundColor: '#172033' },
    continueButton: { backgroundColor: '#5B4B8A' },
  }}
  builders={{
    header: ({ defaultChild }) => defaultChild,
  }}
  onCheckout={continueWithHandoff}
/>

The pricing formatter changes display only. Selection, hold totals, and the trusted server remain authoritative.

Compose a host-owned layout

SeatLayerPickerScope owns one controller and the latest read-only picker state. Every standalone part reads the same scope, resolved theme, capabilities, presentation state, and actions.

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

<SeatLayerPickerScope configuration={configuration} themeMode="auto">
  <SeatLayerPickerHeader />
  <SeatLayerPickerHoldCountdown />
  <SeatLayerPriceLegend />
  <SeatLayerFloorStrip />
  <View style={{ flex: 1, position: 'relative' }}>
    <SeatLayerPickerChart style={{ flex: 1 }} />
    <SeatLayerPickerViewModeControl />
    <SeatLayerMapControls
      includeViewModeControl={false}
      showAccessibilityControl={false}
    />
    <SeatLayerPickerAccessibilityFilters />
  </View>
  <SeatLayerDockBar />
  <SeatLayerCartSheet
    expanded={isCartExpanded}
    onExpandedChanged={setCartExpanded}
    onCheckout={continueWithHandoff}
  />
</SeatLayerPickerScope>

Call useSeatLayerPicker() inside the scope when a host component needs the latest state, resolved theme, capability availability, presentation state, or typed actions. Do not create a second chart for the same buyer flow.

Public component groups

Buyer job Public parts
Identity and navigation SeatLayerPickerHeader, SeatLayerFloorStrip, section navigator, SeatLayerDockBar
Map and filters SeatLayerPickerChart, SeatLayerMapControls, view-mode control, price legend, accessibility filters
Decisions Confirmation, tier choice, GA/table prompts, best-available form
Cart and holds Dense ticket lines, cart list/sheet, countdown, hold-lapse notice, undo
Immersive views Venue 3D navigation and seat-view/panorama chrome
System states Loading, retryable/fatal error, empty/sold-out/sales-closed, action error
Truth indicators Test Mode and required bottom-right SeatLayer attribution

The component catalogue also exports ticket-line grouping utilities so custom carts can reuse canonical ordering and folding rules rather than reconstructing them from low-level inventory data.

State and action guarantees

  • One scope owns one controller and one picker state.
  • Published state is read-only and represents the complete current picker.
  • Stale updates and updates for another event are ignored.
  • Inventory-changing actions are serialized.
  • Optional controls appear only when the negotiated capability exists.
  • Repeated checkout taps join one flight.
  • Ordinary picker state omits the opaque hold ID.
  • SeatLayerPickerCheckoutHandoff crosses that boundary exactly once.
  • A rejected host callback rejects that handoff and restores a recoverable state.

Use useSeatLayerPicker() actions rather than mutating picker state locally.

Lifecycle, Back, and recovery

The ready picker observes app state, refreshes availability when supported, reconciles a lapsed hold, and removes seats that became unavailable while the app was away. A local countdown is only presentation; the server expiry and current SDK state are authoritative.

The Back ladder closes the most local decision first: quantity or confirmation, expanded cart, panorama/3D, focused section, venue, then the host route. Custom layouts must keep equivalent behavior around the same scoped actions.

Test Mode and attribution

Test Mode follows authoritative Event state and must remain visible. 0.3.4 keeps required Powered by SeatLayer attribution at the safe bottom-right edge in compact and wide layouts. Attribution follows the SeatLayer account configuration and cannot be overridden by client-side styles or builders.

Production validation

  • Pin @seatlayer/react-native@0.3.4 and react-native-webview deliberately.
  • Validate Expo Go/development builds and Community CLI paths you support.
  • Test compact/wide layout, safe areas, rotation, Back, background/foreground, process restoration, hold lapse, checkout rejection, and picker load failure.
  • Exercise real tiers, accessibility filters, GA/tables, 3D, panorama, Test Mode, and attribution with hosted events.
  • Test supported physical iOS and Android devices before rollout.
  • Confirm the backend inspects the hold and reuses one booking reference for retries.

Product scope

The native picker selects one Event. It does not accept a Performance Group or Season as native configuration.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close