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.
SeatLayerPickerCheckoutHandoffcrosses 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.4andreact-native-webviewdeliberately. - 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.