Files
2026-09-04 09:04:51 -07:00

203 lines
5.4 KiB
Plaintext

---
title: Native UI
description: Optional native integrations for better performance and UX
name: native
---
# Native Integrations
Gui components work great out of the box, but several offer optional native
integrations for improved performance and platform-native UX. All native
integrations are opt-in - components work without them, just with slightly
different behavior.
## @hanzogui/native Package
The `@hanzogui/native` package provides setup utilities for native integrations.
Import the setup modules at your app's entry point, before any Gui imports.
```bash
npm install @hanzogui/native
```
<Notice>
`@hanzogui/native` is a light setup package. When you use one of its optional
integrations, make sure the matching native dependency is installed in your app as well,
such as `react-native-gesture-handler`, `react-native-teleport`, `zeego`, or `burnt`. In
a monorepo, install those native packages in the parent app or workspace root rather
than a leaf package.
</Notice>
## Portal
**Native portals preserve React context** - the default implementation on native
uses a JS-based approach that breaks React context, or requires you to hoist data
awkwardly. With native portals, your custom contexts (navigation, app state)
work inside Sheet, Dialog, Popover, and other portaled content.
### Setup
```bash
npm install react-native-teleport
```
```tsx
// App.tsx - before any Gui imports
import '@hanzogui/native/setup-teleport'
```
See [Portal docs](/docs/components/portal) for full details.
## Gesture Handler
**Native gesture handling** - powers two features:
1. **Press events** - `onPress` uses RNGH for more reliable press detection with
proper gesture coordination. Matches RN Pressable semantics where only the
innermost pressable fires (no double-firing with nested buttons).
2. **Sheet gestures** - makes sheets feel smoother and not get confused with
scrollable content during drags.
### Setup
```bash
npm install react-native-gesture-handler
```
```tsx
// App.tsx - before any Gui imports
import '@hanzogui/native/setup-gesture-handler'
import { GestureHandlerRootView } from 'react-native-gesture-handler'
export default function App() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>{/* Your app */}</GestureHandlerRootView>
)
}
```
### Selective Features
If you only want RNGH for specific features, use the configurable setup:
```tsx
import { setupGestureHandler } from '@hanzogui/native/setup-gesture-handler'
// only use RNGH for sheets, not press events
setupGestureHandler({ pressEvents: false, sheet: true })
// only use RNGH for press events, not sheets
setupGestureHandler({ pressEvents: true, sheet: false })
```
### Press Event Behavior
With RNGH enabled, `onPress` follows RN Pressable semantics:
- **Nested pressables** - only the innermost fires (no event bubbling)
- **Web parity** - `onPress` calls `stopPropagation()` automatically
- **Use `onClick` on web** if you need standard DOM event bubbling
This aligns to the React Native default behavior of Pressable.
### PressBoundary
If you need a non-Gui native wrapper to block a parent Gui pressable,
use `PressBoundary` from `@hanzogui/native/gesture-handler`.
This is useful when mixing Gui pressables with React Native `Pressable`,
custom native wrappers, or other components that don't use Gui's native
press ownership automatically.
```tsx
import { PressBoundary } from '@hanzogui/native/gesture-handler'
import { Pressable } from 'react-native'
export function AvatarLink() {
return (
<PressBoundary debugName="AvatarLink">
<Pressable onPress={() => {}}>{/* your content */}</Pressable>
</PressBoundary>
)
}
```
`PressBoundary` only coordinates with Gui's native press ownership. It does
not monkey-patch React Native bubbling semantics in general.
Native `Menu.Trigger` and `ContextMenu.Trigger` already do this automatically,
so you should not need extra wrappers or empty `onPress` handlers around them.
See [Sheet docs](/docs/components/sheet) for full details.
## Menu & ContextMenu
**Native menus** - renders platform-native context menus instead of custom
overlays. Uses iOS's native menu API for haptics, blur effects, and system
integration.
### Setup
```bash
npm install zeego @react-native-menu/menu react-native-ios-context-menu react-native-ios-utilities sf-symbols-typescript
```
```tsx
// App.tsx - before any Gui imports
import '@hanzogui/native/setup-zeego'
```
Then use the `native` prop:
```tsx
<Menu native>{/* menu content */}</Menu>
```
See [Menu docs](/docs/components/menu) and
[ContextMenu docs](/docs/components/context-menu) for full details.
## Toast
**Native toasts** - uses platform-native toast implementations:
- iOS: SPIndicator (system-style indicators)
- Android: ToastAndroid
- Web: Notification API
### Setup
```bash
npm install burnt
```
```tsx
// App.tsx - before any Gui imports
import '@hanzogui/native/setup-burnt'
```
Then use the `native` prop on ToastProvider:
```tsx
<Toast.Provider native>{/* your app */}</Toast.Provider>
```
See [Toast docs](/docs/components/toast) for full details.
## LinearGradient
**Native gradients** - uses `expo-linear-gradient` for high-performance native gradient rendering.
### Setup
```bash
npm install expo-linear-gradient
```
```tsx
// App.tsx - before any Gui imports
import '@hanzogui/native/setup-expo-linear-gradient'
```
See [LinearGradient docs](/docs/components/linear-gradient) for full details.