Skip to content

Keyboard Aware Screen

Scrollable form-screen shell with bounded width, explicit safe-area ownership, and platform keyboard handling.

  • Category: Layout & surfaces
  • Status: stable public Registry/export-map component family
  • Targets: iOS · Android · Web, subject to the compatibility contract
  • Prerequisites: @beemvp/beeui-ui installed (or this component’s source copied via the Registry CLI below) and, on Web, the BeeUI Tailwind/Uniwind theme CSS loaded — see Start for full platform setup.
  • Source: packages/ui/src/components/keyboard-aware-screen.tsx
import { KeyboardAwareScreen } from '@beemvp/beeui-ui';

There is no documented deep/private source import. For source ownership from a BeeUI checkout:

Terminal window
pnpm beeui add keyboard-aware-screen

Registry (used throughout this page) is BeeUI’s source-ownership manifest — registry/registry.json — that the pnpm beeui/@beemvp/beeui-cli CLI reads to copy a component’s real source into your app and rewrite its internal imports; it is not an npm package index. This component’s own Registry entry: registry/registry.json.

  • Primary export: KeyboardAwareScreen
    • Also routed here, outside the Registry family:
      • keyboard-aware-screen
    • Package export subpath: @beemvp/beeui-ui/keyboard-aware-screen

Exported types: KeyboardAwareScreenContentWidth, KeyboardAwareScreenKeyboardDismissMode, KeyboardAwareScreenProps, KeyboardAwareScreenSafeAreaEdges

The generated API inventory is mechanically joined to packages/ui/src/index.ts, Registry metadata, and the component reference contract. Each type’s field table below is parsed directly from that source, not a second hand-maintained copy; for the fuller behavior narrative see the canonical component behavior catalog.

Stateless scrollable form-screen shell; it owns explicit safe-area edges and platform keyboard avoidance/dismissal defaults, but no routing, form state, validation, auth, or persistence — those stay entirely with the caller.

Prop Type Default Description
children (required) React.ReactNode — Screen content. Composed inside the bounded, scrollable, keyboard-avoiding body.
className string — Extra utility classes, merged after the component’s own via cn(...), so they win on conflict. An escape hatch for source-owned and application work, not a cross-engine portability guarantee.
contentWidth KeyboardAwareScreenContentWidth 'full' Bounded max-width applied to the scrollable content so long-line forms stay readable on wide/tablet/web viewports. Defaults to 'full' (no bound) — opt into a narrower measure for form-style screens.
keyboardScrollMargin number 24 Gap kept between the focused input and the keyboard once scrolled into view on Android. Defaults to 24.
keyboardDismissMode KeyboardAwareScreenKeyboardDismissMode — Maps to the underlying ScrollView’s keyboardDismissMode. Defaults to 'interactive' on iOS and 'on-drag' elsewhere so drag-to-dismiss stays effective on Android, where React Native treats interactive like none.
keyboardShouldPersistTaps ScrollViewProps['keyboardShouldPersistTaps'] 'handled' Maps to the underlying ScrollView’s keyboardShouldPersistTaps. Defaults to 'handled' so taps on interactive children (buttons, links) inside the scroll body do not require a second tap after the keyboard has focus.
safeAreaEdges KeyboardAwareScreenSafeAreaEdges — Safe-area edges this screen owns. Left unset by default: a screen composed under a header/tab-bar shell that already owns safe-area insets should not also apply them here (double-inset). Pass the edges this screen actually touches (e.g. ['top', 'bottom']) when it owns the full window.
testID string — Test identifier. Forwarded to the native testID and, on Web, emitted as data-testid.

Related exported types:

  • KeyboardAwareScreenContentWidth — one of 'sm', 'md', 'lg', 'full'.
  • KeyboardAwareScreenKeyboardDismissMode — alias of NonNullable<ScrollViewProps['keyboardDismissMode']>.
  • KeyboardAwareScreenSafeAreaEdges — alias of NonNullable<React.ComponentProps<typeof SafeArea>['edges']>.

The executable fixtures below are the source-grounded usage examples; consumers should not infer state ownership from DOM structure or another UI library.

  • No additional provider is required by this family. BeeUIProvider remains the recommended application root.
  • Peer/native dependencies visible to this Registry item: react, react-native
  • Registry dependency closure: core-cn, safe-area, theme
  • Safe-area ownership remains explicit: shell surfaces touching system edges opt into SafeArea; components do not silently invent app-shell insets.
  • Web consumers load the BeeUI semantic theme CSS as documented in Web onboarding.

This family ships no platform-specific file, but its source branches on Platform, so some behavior differs by target.

The same public family is exposed across the supported target matrix; meaningful platform differences remain governed by the compatibility contract.

Evidence classes are not equal and this page does not blur them: Web behavior is exercised in a real browser, while iOS and Android carry package/export and native-compile evidence, which is not device-runtime proof. The compatibility contract records which class each claim rests on.

  • Roles this family assigns: none set in keyboard-aware-screen.tsx.
  • Accessibility states and properties it sets: none set in keyboard-aware-screen.tsx.

Keyboard/focus behavior, announcements, Dynamic Type/Web zoom, RTL and reduced-motion expectations are not derived here — see Accessibility overview, Keyboard & focus, RTL/localization and Large text & zoom. BeeUI does not claim universal accessibility certification from automated tests.

  • Style axes: contentWidth (4 values).
  • Class-name surfaces: className.

Colors, spacing and typography come from semantic tokens rather than from values written here — see Theming and Density. A className is an escape hatch for source-owned and application work, not a cross-engine portability guarantee.

Each link below opens the Showcase at that exact example, not at the top of the gallery:

  • basic — smallest meaningful complete usage

The Showcase links demonstrate Web behavior; use the native-preview guide for real simulator/emulator/device paths.

This frame loads the real BeeUI Web Showcase on demand; it is not a second docs-only implementation. It proves browser behavior only. Use native preview for iOS/Android simulator, emulator or device paths.

  • Family root / primary export: KeyboardAwareScreen
    • Exported type surface:
      • KeyboardAwareScreenContentWidth
      • KeyboardAwareScreenKeyboardDismissMode
      • KeyboardAwareScreenProps
      • KeyboardAwareScreenSafeAreaEdges

The tree above is ordinary document structure so it remains readable with keyboard and assistive technology; it is derived from the real public export family rather than a canvas-only diagram.

The following is the exact typechecked runtime Showcase fixture selected for this live preview: apps/showcase/patterns/account-settings/components/settings-screen-shell.tsx. Runtime gallery/pattern sources are preferred over test harnesses, and the displayed source and executable source are the same file; there is no separately maintained demo snippet.

import { Box, KeyboardAwareScreen, Screen, Text, VStack } from '@beemvp/beeui-ui';
import * as React from 'react';
import { ScrollView } from 'react-native';
export type SettingsScreenShellProps = {
children: React.ReactNode;
description?: string;
eyebrow?: string;
keyboardAware?: boolean;
testID?: string;
title: string;
};
export function SettingsScreenShell({
children,
description,
eyebrow,
keyboardAware = false,
testID,
title,
}: SettingsScreenShellProps) {
const header = (
<VStack gap="sm">
{eyebrow ? (
<Text tone="muted" variant="caption">
{eyebrow}
</Text>
) : null}
<Text className="text-3xl leading-10" variant="title">
{title}
</Text>
{description ? (
<Text tone="muted" variant="body">
{description}
</Text>
) : null}
</VStack>
);
if (keyboardAware) {
return (
<KeyboardAwareScreen contentWidth="md" testID={testID}>
<Box className="flex-1 px-5 py-6 web:py-10">
<VStack gap="xl">
{header}
{children}
</VStack>
</Box>
</KeyboardAwareScreen>
);
}
return (
<Screen testID={testID}>
<ScrollView
contentContainerStyle={{ flexGrow: 1 }}
keyboardDismissMode="interactive"
keyboardShouldPersistTaps="handled"
>
<Box className="mx-auto w-full max-w-[680px] flex-1 px-5 py-6 web:py-10">
<VStack gap="xl">
{header}
{children}
</VStack>
</Box>
</ScrollView>
</Screen>
);
}

Use the code block’s copy affordance to copy the exact fixture. For a smaller app-specific example, start from the public imports shown above and keep only the state your screen owns.

Owns no routing, form state, validation, auth, or persistence.