diff --git a/docs/docs/built-in-adapters/swmansion.md b/docs/docs/built-in-adapters/swmansion.md
index d5ec0f9..a85d236 100644
--- a/docs/docs/built-in-adapters/swmansion.md
+++ b/docs/docs/built-in-adapters/swmansion.md
@@ -66,7 +66,7 @@ The native sheet is intentionally minimal. The adapter layers a few **opt-in** c
| `handle` | `boolean \| { color?, width?, height? } \| ReactElement` | `false` | Renders a grab handle as a chrome layer over the `surface` and insets the content to clear it. Pass `true` for the default pill, an object to restyle it, or a React element for full control. Auto-hidden when dismissal is blocked (see [Close interception](/close-interception)) — a non-draggable sheet showing a grab handle would mislead. |
| `fullHeight` | `boolean` | `false` | Expands the sheet to the full available height (`windowHeight − topInset`). swmansion detents are only `number` / `'content'`, so there's no built-in full-height value — this computes the pixel height for you, safe-area- and rotation-aware, with no `useWindowDimensions` / `useSafeAreaInsets` boilerplate. Ignored when explicit `detents` are passed. |
| `fillContent` | `boolean` | _auto_ | Stretches the content to fill the sheet (`flex: 1`), so a `flex: 1` scrollable expands and a bottom footer pins to the bottom instead of floating up under the content. Auto and rarely set by hand: `true` for fixed-height sheets (numeric detents or `fullHeight`), `false` for content-sized ones (which must size to their content). Pass a boolean to override. |
-| `keyboardBehavior` | `'none' \| 'inset'` | `'none'` | Keyboard avoidance — the native sheet has none, so an input near the bottom would sit under the keyboard. `'inset'` keeps a content-sized sheet's inputs visible: it pads the content by the keyboard height, and because the sheet is bottom-anchored and sizes to its content it re-measures taller and lifts the content clear of the keyboard (native-iOS behavior). No-op for fixed-height sheets (numeric detents / `fullHeight`) — they can't grow, so put a scrollable inside instead. Reads the keyboard height from `react-native-keyboard-controller` (see below). |
+| `keyboardBehavior` | `'none' \| 'inset'` | `'none'` | Keyboard avoidance — the native sheet has none. `'inset'` insets the content by the keyboard height (works for both content-sized and fixed-height sheets); `'none'` lets the content handle it. See [Keyboard avoidance](#keyboard-avoidance) for when to use which. Reads the keyboard height from `react-native-keyboard-controller`. |
| `cornerRadius` | `number` | _surface default_ | Top corner radius, applied to the default surface **and** used to clip the content to those corners, so opaque content (e.g. a non-transparent header flush to the top) can't square off the rounded corners. Pass `0` for a flat top. With a custom `surface`, content clipping is off unless you set this to match your surface's radius (the adapter can't infer a custom surface's corners). |
```tsx
@@ -84,22 +84,65 @@ The native sheet is intentionally minimal. The adapter layers a few **opt-in** c
}>
{/* ... */}
+```
+
+:::info `keyboardBehavior="inset"` needs an optional peer
+This is the only convenience with an extra dependency: it reads the keyboard height from [`react-native-keyboard-controller`](https://kirillzyusko.github.io/react-native-keyboard-controller/), declared as an **optional** peer. If the package isn't installed, the sheet renders without keyboard avoidance and logs a one-time dev warning — it never crashes. Install it only if you use `keyboardBehavior="inset"`:
+
+```bash
+npm install react-native-keyboard-controller
+```
+:::
+
+## Keyboard avoidance
+
+The native swmansion sheet does nothing about the keyboard, so a `TextInput` near the bottom sits under it. `keyboardBehavior` picks **one** layer to handle this — the sheet, or the content. Never both.
+
+### `'inset'` — the sheet handles it
-// Content-sized sheet with a text input that should stay above the keyboard.
+The sheet pads its content by the keyboard height. The effect adapts to the sheet's size automatically:
+
+- **Content-sized** sheet (`'content'` detent): it re-measures taller and the added strip hides behind the keyboard, lifting the content clear of it — matching native iOS.
+- **Fixed-height** sheet (numeric `detents` / `fullHeight`): the content area shrinks by the keyboard height, so a scrollable child scrolls within the remaining space above the keyboard.
+
+```tsx
+// Content-sized sheet with an input that should stay above the keyboard.
+
+// Full-height list with a search field in the header.
+
+ } /* … */ />
+
```
-:::info `keyboardBehavior="inset"` needs an optional peer
-This is the only convenience with an extra dependency: it reads the keyboard height from [`react-native-keyboard-controller`](https://kirillzyusko.github.io/react-native-keyboard-controller/), declared as an **optional** peer. If the package isn't installed, the sheet renders without keyboard avoidance and logs a one-time dev warning — it never crashes. Install it only if you use `keyboardBehavior="inset"`:
+The content must be a **plain** scrollable/view. For a fixed-height sheet the scrollable should fill (`flex: 1`) so it can shrink. Do **not** also nest a keyboard-aware scrollable inside — that double-insets and over-scrolls the content (the input jumps out of view on focus).
-```bash
-npm install react-native-keyboard-controller
+`'inset'` keeps the focused input *visible*, but it does not *auto-scroll* to a specific input deep in the content. That's fine for a search field in a header (already at the top); for a long form, see `'none'`.
+
+### `'none'` — the content handles it
+
+The sheet ignores the keyboard. Put a keyboard-aware scrollable inside that pads by the keyboard height **and** auto-scrolls the focused field into view — e.g. `KeyboardAwareScrollView` from `react-native-keyboard-controller`. Use this for **multi-field forms**, where focusing a field lower down should bring it above the keyboard.
+
+```tsx
+
+
+ {/* many fields — focusing one scrolls it into view */}
+
+
```
-:::
+
+### Which one?
+
+| Content | `keyboardBehavior` |
+| --- | --- |
+| List, simple scroll, search-in-header, short form | `'inset'` (plain scrollable/view inside) |
+| Multi-field form that must auto-scroll to the focused field | `'none'` (keyboard-aware scrollable inside) |
+
+Pick exactly one. Combining `'inset'` with a keyboard-aware scrollable lifts the content twice.
## Backdrop
diff --git a/src/adapters/swmansion/SwmansionKeyboardInset.tsx b/src/adapters/swmansion/SwmansionKeyboardInset.tsx
index 9fb8dc5..5825dea 100644
--- a/src/adapters/swmansion/SwmansionKeyboardInset.tsx
+++ b/src/adapters/swmansion/SwmansionKeyboardInset.tsx
@@ -33,9 +33,9 @@ interface Props {
}
function KeyboardInsetActive({ children, style }: Props) {
- // Bottom-anchored, content-sized sheets re-measure when their content grows,
- // so padding the content by the keyboard height lifts it clear of the keyboard
- // (the added strip hides behind the keyboard) — matching native iOS.
+ // Pad by the keyboard height: a content-sized sheet re-measures taller (the
+ // strip hides behind the keyboard); a fixed-height one (gets `flex: 1` via
+ // `style`) shrinks its scroll area above the keyboard instead.
const keyboardHeight = keyboardController!.useKeyboardState(
(state) => state.height
);
diff --git a/src/adapters/swmansion/SwmansionSheetAdapter.tsx b/src/adapters/swmansion/SwmansionSheetAdapter.tsx
index 9294ed0..bb929ce 100644
--- a/src/adapters/swmansion/SwmansionSheetAdapter.tsx
+++ b/src/adapters/swmansion/SwmansionSheetAdapter.tsx
@@ -155,22 +155,16 @@ export interface SwmansionSheetAdapterProps
*/
fillContent?: boolean;
/**
- * Keyboard avoidance for the sheet's content. The native swmansion sheet has
- * none of its own, so a `TextInput` near the bottom would sit under the
- * keyboard.
+ * Keyboard avoidance for the sheet's content.
*
- * - `'none'` (default) — no avoidance; the raw native behavior.
- * - `'inset'` — keeps a content-sized sheet's inputs above the keyboard.
- * Because the sheet is bottom-anchored and sizes to its content, padding the
- * content by the keyboard height re-measures the sheet taller and lifts the
- * content clear of the keyboard (the added strip hides behind it) — matching
- * native iOS. No-op for fixed-height sheets (numeric `detents` /
- * {@link fullHeight}): they can't grow, so put a scrollable inside and let it
- * scroll the focused input into view instead.
+ * - `'none'` (default) — the content owns the keyboard (use a keyboard-aware
+ * scrollable inside).
+ * - `'inset'` — the sheet insets its content by the keyboard height (content
+ * must be a plain scrollable/view; don't also nest a keyboard-aware one).
*
- * `'inset'` reads the keyboard height from the optional peer
- * `react-native-keyboard-controller`. If it isn't installed the sheet renders
- * without avoidance (a one-time dev warning is logged) — it never crashes.
+ * `'inset'` needs the optional peer `react-native-keyboard-controller`; without
+ * it the sheet renders without avoidance. See the
+ * Keyboard avoidance guide for when to use which.
*/
keyboardBehavior?: 'none' | 'inset';
/**
@@ -426,7 +420,9 @@ export const SwmansionSheetAdapter = React.forwardRef<
borderTopRightRadius: surfaceRadius,
}
: null;
- const needsKeyboardInset = keyboardBehavior === 'inset' && !shouldFill;
+ // Applies to every sheet size: a content-sized sheet re-measures taller, a
+ // fixed-height one (carries `fillStyle`) shrinks its scroll area instead.
+ const needsKeyboardInset = keyboardBehavior === 'inset';
let content = children;
if (needsKeyboardInset) {