0
# React Native Features
1
2
React Native-specific enhancements including layout measurement, pressability handling, platform optimizations, and cross-platform compatibility features.
3
4
## Capabilities
5
6
### Layout Measurement
7
8
Element layout measurement system providing React Native-style layout information on both platforms.
9
10
```typescript { .api }
11
/**
12
* Hook for tracking element layout changes
13
* @param stateRef - Component state reference
14
* @param onLayout - Layout change callback
15
* @returns Layout measurement utilities
16
*/
17
function useElementLayout(
18
stateRef?: React.MutableRefObject<any>,
19
onLayout?: (event: LayoutEvent) => void
20
): LayoutMeasurement;
21
22
/**
23
* Set the layout measurement strategy
24
* @param strategy - Measurement strategy to use
25
*/
26
function setOnLayoutStrategy(strategy: LayoutStrategy): void;
27
28
/**
29
* Create element measurement function
30
* @param element - Element to measure
31
* @returns Measurement function
32
*/
33
function createMeasure(element: Element): MeasureFunction;
34
35
/**
36
* Create window-relative measurement function
37
* @param element - Element to measure
38
* @returns Window measurement function
39
*/
40
function createMeasureInWindow(element: Element): MeasureInWindowFunction;
41
42
/**
43
* Create layout measurement function
44
* @param element - Element to measure
45
* @returns Layout measurement function
46
*/
47
function createMeasureLayout(element: Element): MeasureLayoutFunction;
48
49
interface LayoutEvent {
50
nativeEvent: {
51
layout: {
52
x: number;
53
y: number;
54
width: number;
55
height: number;
56
};
57
};
58
}
59
60
type LayoutStrategy = 'native' | 'web';
61
62
interface LayoutMeasurement {
63
x: number;
64
y: number;
65
width: number;
66
height: number;
67
}
68
69
type MeasureFunction = (callback: (x: number, y: number, width: number, height: number, pageX: number, pageY: number) => void) => void;
70
71
type MeasureInWindowFunction = (callback: (x: number, y: number, width: number, height: number) => void) => void;
72
73
type MeasureLayoutFunction = (relativeTo: Element, callback: (left: number, top: number, width: number, height: number) => void) => void;
74
```
75
76
**Usage Examples:**
77
78
```typescript
79
import { useElementLayout, View, Text } from "@tamagui/core";
80
81
function MeasuredComponent() {
82
const [layout, setLayout] = useState(null);
83
84
const handleLayout = (event: LayoutEvent) => {
85
const { x, y, width, height } = event.nativeEvent.layout;
86
setLayout({ x, y, width, height });
87
};
88
89
useElementLayout(undefined, handleLayout);
90
91
return (
92
<View onLayout={handleLayout}>
93
<Text>
94
{layout && `Size: ${layout.width}x${layout.height}`}
95
</Text>
96
</View>
97
);
98
}
99
100
// Manual measurement
101
function ManualMeasurement() {
102
const elementRef = useRef(null);
103
104
const measureElement = () => {
105
if (elementRef.current?.measure) {
106
elementRef.current.measure((x, y, width, height, pageX, pageY) => {
107
console.log('Element measurements:', { x, y, width, height, pageX, pageY });
108
});
109
}
110
};
111
112
return (
113
<View ref={elementRef}>
114
<button onClick={measureElement}>Measure Me</button>
115
</View>
116
);
117
}
118
```
119
120
### Pressability System
121
122
React Native pressability system for handling touch interactions with smooth press states.
123
124
```typescript { .api }
125
/**
126
* Hook for React Native-style pressability (native platform only)
127
* @param events - Event handlers for press interactions
128
* @returns Pressability props to spread on components
129
*/
130
function usePressability(events?: PressabilityEvents): PressabilityConfig;
131
132
interface PressabilityEvents {
133
/** Called when press begins */
134
onPressIn?: (event: PressEvent) => void;
135
/** Called when press ends */
136
onPressOut?: (event: PressEvent) => void;
137
/** Called when press completes */
138
onPress?: (event: PressEvent) => void;
139
/** Called when press is cancelled */
140
onPressCancel?: (event: PressEvent) => void;
141
/** Called when long press is detected */
142
onLongPress?: (event: PressEvent) => void;
143
/** Hit area expansion */
144
hitSlop?: HitSlop;
145
/** Delay before onPressIn */
146
delayPressIn?: number;
147
/** Delay before onPressOut */
148
delayPressOut?: number;
149
/** Delay before onLongPress */
150
delayLongPress?: number;
151
/** Minimum press duration */
152
minPressDuration?: number;
153
}
154
155
interface PressabilityConfig {
156
onPressIn?: (event: PressEvent) => void;
157
onPressOut?: (event: PressEvent) => void;
158
onResponderGrant?: (event: ResponderEvent) => void;
159
onResponderMove?: (event: ResponderEvent) => void;
160
onResponderRelease?: (event: ResponderEvent) => void;
161
onResponderTerminate?: (event: ResponderEvent) => void;
162
onStartShouldSetResponder?: () => boolean;
163
onMoveShouldSetResponder?: () => boolean;
164
}
165
166
interface PressEvent {
167
nativeEvent: {
168
locationX: number;
169
locationY: number;
170
pageX: number;
171
pageY: number;
172
target: any;
173
timestamp: number;
174
};
175
}
176
177
interface HitSlop {
178
top?: number;
179
left?: number;
180
bottom?: number;
181
right?: number;
182
}
183
```
184
185
**Usage Examples:**
186
187
```typescript
188
import { usePressability, View, Text } from "@tamagui/core";
189
190
function PressableButton({ onPress, children }) {
191
const pressability = usePressability({
192
onPress,
193
onPressIn: () => console.log('Press started'),
194
onPressOut: () => console.log('Press ended'),
195
onLongPress: () => console.log('Long press detected'),
196
hitSlop: { top: 10, left: 10, bottom: 10, right: 10 },
197
delayLongPress: 500,
198
});
199
200
return (
201
<View
202
{...pressability}
203
style={{
204
padding: 16,
205
backgroundColor: '#007AFF',
206
borderRadius: 8,
207
}}
208
>
209
<Text style={{ color: 'white', textAlign: 'center' }}>
210
{children}
211
</Text>
212
</View>
213
);
214
}
215
```
216
217
### Responder Events
218
219
React Native responder event system for advanced touch handling.
220
221
```typescript { .api }
222
/**
223
* Hook for React Native responder events (web platform)
224
* @param stateRef - Component state reference
225
* @param props - Component props with responder events
226
*/
227
function useResponderEvents(
228
stateRef: React.MutableRefObject<any>,
229
props?: ResponderEventProps
230
): void;
231
232
interface ResponderEventProps {
233
/** Should respond to move events */
234
onMoveShouldSetResponder?: (event: ResponderEvent) => boolean;
235
/** Should respond to move events (capture phase) */
236
onMoveShouldSetResponderCapture?: (event: ResponderEvent) => boolean;
237
/** Responder granted */
238
onResponderGrant?: (event: ResponderEvent) => void;
239
/** Responder rejected */
240
onResponderReject?: (event: ResponderEvent) => void;
241
/** Responder started */
242
onResponderStart?: (event: ResponderEvent) => void;
243
/** Responder moved */
244
onResponderMove?: (event: ResponderEvent) => void;
245
/** Responder ended */
246
onResponderEnd?: (event: ResponderEvent) => void;
247
/** Responder released */
248
onResponderRelease?: (event: ResponderEvent) => void;
249
/** Responder terminated */
250
onResponderTerminate?: (event: ResponderEvent) => void;
251
/** Responder termination requested */
252
onResponderTerminationRequest?: (event: ResponderEvent) => boolean;
253
/** Should respond to start events */
254
onStartShouldSetResponder?: (event: ResponderEvent) => boolean;
255
/** Should respond to start events (capture phase) */
256
onStartShouldSetResponderCapture?: (event: ResponderEvent) => boolean;
257
/** Should respond to scroll events */
258
onScrollShouldSetResponder?: (event: ResponderEvent) => boolean;
259
/** Should respond to scroll events (capture phase) */
260
onScrollShouldSetResponderCapture?: (event: ResponderEvent) => boolean;
261
/** Should respond to selection change events */
262
onSelectionChangeShouldSetResponder?: (event: ResponderEvent) => boolean;
263
/** Should respond to selection change events (capture phase) */
264
onSelectionChangeShouldSetResponderCapture?: (event: ResponderEvent) => boolean;
265
}
266
267
interface ResponderEvent {
268
nativeEvent: {
269
changedTouches: Touch[];
270
identifier: number;
271
locationX: number;
272
locationY: number;
273
pageX: number;
274
pageY: number;
275
target: any;
276
timestamp: number;
277
touches: Touch[];
278
};
279
}
280
```
281
282
### Platform-Specific Optimizations
283
284
Functions and components for React Native performance optimizations.
285
286
```typescript { .api }
287
/**
288
* Create optimized view for React Native platform
289
* @param children - Child components
290
* @param props - View props
291
* @param baseViews - Base React Native components
292
* @returns Optimized React Native view
293
*/
294
function createOptimizedView(
295
children: React.ReactNode,
296
props: Record<string, any>,
297
baseViews: BaseViews
298
): React.ReactElement;
299
300
/**
301
* Get base React Native components
302
* @returns Object with React Native base components
303
*/
304
function getBaseViews(): BaseViews;
305
306
/**
307
* Add React Native version-specific valid styles
308
*/
309
function addNativeValidStyles(): void;
310
311
interface BaseViews {
312
View: React.ComponentType<any>;
313
Text: React.ComponentType<any>;
314
StyleSheet: any;
315
TextAncestor: React.ComponentType<any> | undefined;
316
Pressable: React.ComponentType<any>;
317
}
318
```
319
320
### Style Injection (Development)
321
322
Style injection utilities for development mode (web platform).
323
324
```typescript { .api }
325
/**
326
* Inject CSS styles dynamically for development mode
327
* @param options - Injection options
328
*/
329
function injectStyles(options: InjectStylesOptions): void;
330
331
interface InjectStylesOptions {
332
/** File path for CSS identification */
333
filePath: string;
334
/** CSS string to inject */
335
css: string;
336
}
337
```
338
339
**Usage Examples:**
340
341
```typescript
342
import { injectStyles } from "@tamagui/core";
343
344
// Development-time style injection
345
if (process.env.NODE_ENV === 'development') {
346
injectStyles({
347
filePath: 'components/Button.tsx',
348
css: `
349
.debug-button {
350
border: 2px solid red !important;
351
}
352
`,
353
});
354
}
355
```
356
357
### React Native Props Support
358
359
Enhanced components with full React Native prop support.
360
361
```typescript { .api }
362
/**
363
* Enhanced View component with React Native props
364
*/
365
declare const View: TamaguiComponent<
366
TamaDefer,
367
TamaguiElement,
368
RNTamaguiViewNonStyleProps,
369
StackStyleBase,
370
{}
371
>;
372
373
/**
374
* Enhanced Text component with React Native text props
375
*/
376
declare const Text: TamaguiComponent<
377
TamaDefer,
378
TamaguiTextElement,
379
RNTamaguiTextNonStyleProps,
380
TextStylePropsBase,
381
{}
382
>;
383
384
interface RNTamaguiViewNonStyleProps extends StackNonStyleProps {
385
// React Native View props
386
/** Accessibility properties */
387
accessible?: boolean;
388
accessibilityActions?: AccessibilityAction[];
389
accessibilityLabel?: string;
390
accessibilityLabelledBy?: string;
391
accessibilityRole?: AccessibilityRole;
392
accessibilityState?: AccessibilityState;
393
accessibilityValue?: AccessibilityValue;
394
accessibilityHint?: string;
395
accessibilityLanguage?: string;
396
397
/** Android-specific props */
398
collapsable?: boolean;
399
focusable?: boolean;
400
401
/** Layout and interaction */
402
onLayout?: (event: LayoutEvent) => void;
403
onStartShouldSetResponder?: (event: ResponderEvent) => boolean;
404
onMoveShouldSetResponder?: (event: ResponderEvent) => boolean;
405
onResponderGrant?: (event: ResponderEvent) => void;
406
onResponderMove?: (event: ResponderEvent) => void;
407
onResponderRelease?: (event: ResponderEvent) => void;
408
onResponderTerminate?: (event: ResponderEvent) => void;
409
onResponderTerminationRequest?: (event: ResponderEvent) => boolean;
410
411
/** Pointer events */
412
pointerEvents?: 'auto' | 'none' | 'box-none' | 'box-only';
413
414
/** Test IDs */
415
testID?: string;
416
nativeID?: string;
417
418
/** Hit testing */
419
hitSlop?: HitSlop;
420
421
/** Remove clipped subviews (performance) */
422
removeClippedSubviews?: boolean;
423
}
424
425
interface RNTamaguiTextNonStyleProps extends TextNonStyleProps {
426
// React Native Text props
427
/** Text selection */
428
selectable?: boolean;
429
selectionColor?: string;
430
431
/** Text styling */
432
allowFontScaling?: boolean;
433
maxFontSizeMultiplier?: number;
434
minimumFontScale?: number;
435
suppressHighlighting?: boolean;
436
437
/** Text measurement */
438
adjustsFontSizeToFit?: boolean;
439
numberOfLines?: number;
440
ellipsizeMode?: 'head' | 'middle' | 'tail' | 'clip';
441
442
/** Text events */
443
onTextLayout?: (event: TextLayoutEvent) => void;
444
onPress?: (event: PressEvent) => void;
445
onPressIn?: (event: PressEvent) => void;
446
onPressOut?: (event: PressEvent) => void;
447
onLongPress?: (event: PressEvent) => void;
448
449
/** Accessibility */
450
accessible?: boolean;
451
accessibilityLabel?: string;
452
accessibilityRole?: AccessibilityRole;
453
accessibilityState?: AccessibilityState;
454
}
455
```
456
457
### Platform Detection
458
459
Constants and utilities for platform-specific behavior.
460
461
```typescript { .api }
462
/** Web platform detection */
463
declare const isWeb: boolean;
464
465
/** Server environment detection */
466
declare const isServer: boolean;
467
468
/** Client environment detection */
469
declare const isClient: boolean;
470
471
/** Android platform detection */
472
declare const isAndroid: boolean;
473
474
/** iOS platform detection */
475
declare const isIos: boolean;
476
477
/** Touch capability detection */
478
declare const isTouchable: boolean;
479
480
/** Web touch capability detection */
481
declare const isWebTouchable: boolean;
482
483
/**
484
* SSR-safe useLayoutEffect hook
485
*/
486
declare const useIsomorphicLayoutEffect: typeof React.useLayoutEffect;
487
```
488
489
**Usage Examples:**
490
491
```typescript
492
import { isWeb, isAndroid, isIos, View, Text } from "@tamagui/core";
493
494
function PlatformSpecificComponent() {
495
return (
496
<View>
497
{isWeb && <Text>Web platform</Text>}
498
{isAndroid && <Text>Android platform</Text>}
499
{isIos && <Text>iOS platform</Text>}
500
</View>
501
);
502
}
503
504
// Platform-specific styling
505
const PlatformView = styled(View, {
506
backgroundColor: '$background',
507
508
...isWeb && {
509
cursor: 'pointer',
510
userSelect: 'none',
511
},
512
513
...isAndroid && {
514
elevation: 4,
515
},
516
517
...isIos && {
518
shadowOpacity: 0.3,
519
shadowRadius: 4,
520
shadowOffset: { width: 0, height: 2 },
521
},
522
});
523
```
524
525
## Types
526
527
```typescript { .api }
528
interface AccessibilityAction {
529
name: string;
530
label?: string;
531
}
532
533
type AccessibilityRole =
534
| 'none'
535
| 'button'
536
| 'link'
537
| 'search'
538
| 'image'
539
| 'keyboardkey'
540
| 'text'
541
| 'adjustable'
542
| 'imagebutton'
543
| 'header'
544
| 'summary'
545
| 'alert'
546
| 'checkbox'
547
| 'combobox'
548
| 'menu'
549
| 'menubar'
550
| 'menuitem'
551
| 'progressbar'
552
| 'radio'
553
| 'radiogroup'
554
| 'scrollbar'
555
| 'spinbutton'
556
| 'switch'
557
| 'tab'
558
| 'tablist'
559
| 'timer'
560
| 'toolbar';
561
562
interface AccessibilityState {
563
disabled?: boolean;
564
selected?: boolean;
565
checked?: boolean | 'mixed';
566
busy?: boolean;
567
expanded?: boolean;
568
}
569
570
interface AccessibilityValue {
571
min?: number;
572
max?: number;
573
now?: number;
574
text?: string;
575
}
576
577
interface TextLayoutEvent {
578
nativeEvent: {
579
lines: TextLayoutLine[];
580
};
581
}
582
583
interface TextLayoutLine {
584
text: string;
585
x: number;
586
y: number;
587
width: number;
588
height: number;
589
descender: number;
590
capHeight: number;
591
baseline: number;
592
xHeight: number;
593
}
594
```