truesheet-usage
Consumer-side guide for integrating @lodev09/react-native-true-sheet into a React Native app. Use this skill whenever the user wants to add, configure, control, or debug a bottom sheet using TrueSheet — including ref-based sheets, named global sheets, web support with TrueSheetProvider/useTrueSheet, React Navigation or Expo Router sheet flows, Reanimated-driven animations, scrolling content, stacking, headers/footers, detents, side sheets, keyboard handling, dimming, liquid glass, and Jest testing. Also use when the user is migrating from v2 to v3, troubleshooting layout or gesture issues, or asking about any TrueSheet prop, event, or method — even if they don't mention "TrueSheet" by name but describe a bottom sheet in a React Native context.
What this skill does
# TrueSheet Consumer Guide
Use this skill to produce correct, idiomatic code for apps that consume `@lodev09/react-native-true-sheet`. It covers choosing the right integration pattern, applying the public API correctly, and avoiding platform-specific pitfalls.
## Quick Start
The simplest sheet: a ref, a button, and some content.
```tsx
import { useRef } from 'react'
import { Button, Text, View } from 'react-native'
import { TrueSheet } from '@lodev09/react-native-true-sheet'
export function App() {
const sheet = useRef<TrueSheet>(null)
return (
<View>
<Button title="Open" onPress={() => sheet.current?.present()} />
<TrueSheet ref={sheet} detents={['auto']} cornerRadius={24} grabber>
<View style={{ padding: 16 }}>
<Text>Hello from the sheet</Text>
<Button title="Close" onPress={() => sheet.current?.dismiss()} />
</View>
</TrueSheet>
</View>
)
}
```
## Choose the Right Control Pattern
Pick one based on where the trigger lives relative to the sheet and which platforms you target.
| Pattern | When to use | Platform |
|---------|------------|----------|
| **Ref** | Trigger and sheet in the same component | All |
| **Named + global methods** | Trigger is far from the sheet (different screen, deep in tree) | Native only |
| **`TrueSheetProvider` + `useTrueSheet()`** | Web support needed, or you want hook-based control | All (required on web) |
| **`createTrueSheetNavigator()`** | Sheets are part of a navigation flow | All |
| **`ReanimatedTrueSheet`** | You need animated values synced to sheet position | All |
### Ref-based
Already shown in Quick Start. Use `present()`, `dismiss()`, `resize(index)` on the ref.
### Named sheet with global methods (native only)
When the trigger is far from where the sheet renders:
```tsx
// Somewhere in the tree
<TrueSheet name="profile" detents={['auto', 1]}>
<ProfileContent />
</TrueSheet>
// Anywhere else (native only)
await TrueSheet.present('profile')
await TrueSheet.dismiss('profile')
await TrueSheet.resize('profile', 1)
await TrueSheet.dismissAll()
```
Every `name` must be unique. Static methods don't exist on web — use the provider pattern instead.
### Web control with provider
Wrap your app with `TrueSheetProvider` (on native this is a pass-through with zero overhead):
```tsx
import { TrueSheet, TrueSheetProvider, useTrueSheet } from '@lodev09/react-native-true-sheet'
function Toolbar() {
const { present, dismiss } = useTrueSheet()
return <Button title="Open" onPress={() => present('settings')} />
}
export function App() {
return (
<TrueSheetProvider>
<Toolbar />
<TrueSheet name="settings" detents={[0.5, 1]}>
<SettingsContent />
</TrueSheet>
</TrueSheetProvider>
)
}
```
### Navigation (React Navigation / Expo Router)
See [advanced patterns reference](./references/advanced-patterns.md#react-navigation) for full setup with `createTrueSheetNavigator`, Expo Router layouts, screen options, and `useTrueSheetNavigation`.
### Reanimated
See [advanced patterns reference](./references/advanced-patterns.md#reanimated) for `ReanimatedTrueSheet`, `ReanimatedTrueSheetProvider`, and animated values (`animatedPosition`, `animatedIndex`, `animatedDetent`).
## Detents
Detents define the heights the sheet can snap to. You get up to **3 detents**, sorted smallest to largest.
| Value | Meaning |
|-------|---------|
| `'auto'` | Size to fit the content (iOS 16+, Android, Web) |
| `0` – `1` | Fraction of the screen height |
```tsx
// Content-sized sheet
<TrueSheet detents={['auto']} />
// Half and full screen
<TrueSheet detents={[0.5, 1]} />
// Three stops: peek, half, full
<TrueSheet detents={[0.25, 0.5, 1]} />
```
**The one rule you can't break:** never combine `'auto'` with `scrollable`. Auto-sizing needs to measure the full content, but a scrollable sheet clips it — they're fundamentally incompatible. Use fractional detents for scrollable sheets.
## Common Recipes
### Scrollable content
```tsx
<TrueSheet detents={[0.5, 1]} scrollable cornerRadius={24} grabber>
<ScrollView>
{items.map(item => <ItemRow key={item.id} item={item} />)}
</ScrollView>
</TrueSheet>
```
- The `scrollable` prop auto-detects ScrollView/FlatList up to 2 levels deep
- On iOS, scrolling to top expands to next detent — disable with `scrollableOptions={{ scrollingExpandsSheet: false }}`
- On Android, nested scrolling is handled automatically
### Fixed header and footer
```tsx
<TrueSheet
detents={[0.5, 1]}
scrollable
header={
<View style={{ padding: 16 }}>
<Text style={{ fontSize: 18, fontWeight: 'bold' }}>Title</Text>
</View>
}
footer={<BottomActions />}
>
<ScrollView>{/* ... */}</ScrollView>
</TrueSheet>
```
Use the `header` and `footer` props — they render in native container views, so the layout math is handled for you. Don't fake it with absolute positioning.
### Non-dismissible confirmation
```tsx
<TrueSheet
ref={sheet}
detents={['auto']}
dismissible={false}
draggable={false}
dimmed
grabber={false}
>
<View style={{ padding: 24 }}>
<Text>Are you sure?</Text>
<Button title="Confirm" onPress={handleConfirm} />
<Button title="Cancel" onPress={() => sheet.current?.dismiss()} />
</View>
</TrueSheet>
```
### iOS blur background
```tsx
<TrueSheet detents={['auto']} backgroundBlur="system-material">
<View style={{ padding: 16 }}>
<Text>Blurred sheet</Text>
</View>
</TrueSheet>
```
Fine-tune with `blurOptions={{ intensity: 80, interaction: true }}`. Blur is iOS-only.
### Present on mount
```tsx
<TrueSheet detents={['auto', 1]} initialDetentIndex={0} initialDetentAnimated>
<WelcomeContent />
</TrueSheet>
```
### Dimming control
```tsx
// No dimming (allows background interaction)
<TrueSheet dimmed={false} detents={['auto']} />
// Dim only above a certain detent
<TrueSheet detents={['auto', 0.7, 1]} dimmedDetentIndex={1} />
```
### Resize programmatically
`resize()` takes a **detent index**, not a value:
```tsx
const sheet = useRef<TrueSheet>(null)
// detents={[0.3, 0.6, 1]}
await sheet.current?.resize(2) // expands to full (index 2)
```
## Rules That Save Debugging Time
1. **Max 3 detents**, sorted smallest → largest.
2. **Never `'auto'` + `scrollable`** — they're incompatible.
3. **`resize()` takes an index**, not a fraction. `resize(1)` means "go to the second detent."
4. **Sheet names must be unique** across your entire app.
5. **Static methods are native-only** — use `useTrueSheet()` on web.
6. **Don't use `autoFocus` on TextInputs** inside sheets. Focus in `onDidPresent` instead:
```tsx
<TrueSheet onDidPresent={() => inputRef.current?.focus()}>
```
7. **Use `flexGrow: 1`** (not `flex: 1`) inside `GestureHandlerRootView` on Android.
8. **Dismiss sheets before closing Modals** on iOS — React Native has a bug where dismissing a Modal while a sheet is visible causes a blank screen.
9. **Use `header`/`footer` props** for fixed chrome — don't reach for absolute positioning.
10. **Liquid Glass** is automatic on iOS 26+. Set `backgroundColor` to disable it per-sheet, or add `UIDesignRequiresCompatibility` to Info.plist to disable app-wide.
## Platform Differences at a Glance
| Feature | iOS | Android | Web |
|---------|-----|---------|-----|
| `'auto'` detent | iOS 16+ | Yes | Yes |
| `backgroundBlur` | Yes | No | No |
| Liquid Glass | iOS 26+ | No | No |
| Static global methods | Yes | Yes | No (use provider) |
| `scrollable` | Yes | Yes | No |
| `anchor` / side sheets | System-controlled margins | `anchorOffset` prop | `anchorOffset` prop |
| `presentation` | iOS 17+ (iPad) | N/A | Landscape/tablet |
| `detached` mode | No | No | Yes |
| Edge-to-edge | N/A | Auto-detected | N/A |
| Keyboard handling | Built-in | Built-in | N/A |
## Events
The most commonly used events:
| Event | When it fires | Payload |
|-------|--------------|---------|
| `onMount` | Content is mounted and ready | — |
| `onDidPresent` | Sheet finished preRelated in Web Dev
generating-lwc-components
IncludedLightning Web Components with PICKLES methodology and 165-point scoring. Use this skill when the user creates or edits LWC components, builds wire service patterns, or writes Jest tests for LWC. TRIGGER when: user creates/edits LWC components, touches lwc/**/*.js, .html, .css, .js-meta.xml files, or asks about wire service, SLDS, or Jest LWC tests. DO NOT TRIGGER when: Apex classes (use generating-apex), Aura components, or Visualforce.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Set up queries with useQuery, mutations with useMutation, configure QueryClient caching strategies, implement optimistic updates, and handle infinite scroll with useInfiniteQuery. Use when: setting up data fetching in React projects, migrating from v4 to v5, or fixing object syntax required errors, query callbacks removed issues, cacheTime renamed to gcTime, isPending vs isLoading confusion, keepPreviousData removed problems.
document-processor-api
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
nutrient-document-processing
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Covers useMutationState, simplified optimistic updates, throwOnError, network mode (offline/PWA), and infiniteQueryOptions. Use when setting up data fetching, fixing v4→v5 migration errors (object syntax, gcTime, isPending, keepPreviousData), or debugging SSR/hydration issues with streaming server components.
accelint-nextjs-best-practices
IncludedNext.js performance optimization and best practices. Use when writing Next.js code (App Router or Pages Router); implementing Server Components, Server Actions, or API routes; optimizing RSC serialization, data fetching, or server-side rendering; reviewing Next.js code for performance issues; fixing authentication in Server Actions; or implementing Suspense boundaries, parallel data fetching, or request deduplication.