Scaffold
Screen structure for safe areas, top chrome, scrollable content and a fixed footer.
Scaffold anatomy
Scaffold fills the screen, then arranges its regions vertically.
- Scaffold.AppBarHolds navigation, the screen title and contextual actions.
- Scaffold.ContentTakes the available height and owns scrolling by default.
- Scaffold.FooterKeeps the main action visible below the scrolling content.
- safeAreaEdgesProtect content around the status bar and home indicator.
Installation
npx axiom add scaffoldpnpm dlx axiom add scaffoldyarn dlx axiom add scaffoldbun x axiom add scaffoldAlso copies: app-bar and its dependencies. Installs react-native-keyboard-controller and react-native-safe-area-context. Scaffold brings no tokens of its own: it uses the screen background and the bar’s.
Your app needs KeyboardProvider at its root for keyboardAvoiding to work.
Usage
import { Scaffold } from "@/components/ui/scaffold";
<Scaffold>
<Scaffold.AppBar title="Settings" />
<Scaffold.Content>{/* screen content */}</Scaffold.Content>
<Scaffold.Footer>
<Button fullWidth>Save</Button>
</Scaffold.Footer>
</Scaffold>;Props
Scaffold
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Screen regions, usually AppBar, Content and an optional Footer. |
safeAreaEdges | Edge[] | ['top', 'bottom'] | Safe-area edges owned by the screen. Child regions avoid applying the same inset twice. |
background | 'default' | 'subtle' | 'default' | Uses the standard screen background or the grouped-list background. |
keyboardAvoiding | boolean | true | Moves the footer above the keyboard on iOS and resizes available content on Android. |
statusBarStyle | 'auto' | 'light' | 'dark' | 'auto' | Status bar content style. auto follows the resolved color scheme. |
style | StyleProp<ViewStyle> | — | Extra styles for the screen container. |
Scaffold.AppBar
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Convenience title for a standard compact AppBar. |
leading | ReactNode | — | Leading navigation control. |
actions | ReactNode | — | Trailing screen actions. |
...AppBarProps | — | — | Every AppBar prop. Use children instead when you need the compound slots. |
Scaffold.Content
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Main screen content. |
scrollable | boolean | true | Uses a ScrollView. Set it to false for lists, maps or another child that owns scrolling. |
contentContainerStyle | StyleProp<ViewStyle> | — | Styles the inner scroll container, including padding and gaps. |
keyboardShouldPersistTaps | ScrollViewProps['keyboardShouldPersistTaps'] | 'handled' | Controls whether tapping content dismisses the keyboard. |
...ScrollViewProps | — | — | Remaining scroll props when scrollable is true. |
Scaffold.Footer
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Fixed actions shown after the content region. |
bordered | boolean | false | Draws a hairline above the footer when scrolling content passes behind it. |
safeArea | boolean | false | Adds the bottom safe-area inset to the footer. Leave it off while the root owns the bottom edge, which it does by default — otherwise the inset lands twice. |
style | StyleProp<ViewStyle> | — | Extra footer styles. |
Use cases
Form with a fixed action
Let the fields scroll while the main action stays reachable. The footer moves above the keyboard instead of covering the focused field.
<Scaffold keyboardAvoiding>
<Scaffold.AppBar title="New address" leading={<CloseButton />} />
<Scaffold.Content contentContainerStyle={styles.form}>
<AddressFields />
</Scaffold.Content>
<Scaffold.Footer>
<Button size="lg" fullWidth onPress={save}>
Save address
</Button>
</Scaffold.Footer>
</Scaffold>Grouped settings screen
Use the subtle background with inset lists. A FlatList owns scrolling here, so Scaffold.Content renders a plain view.
<Scaffold background="subtle">
<Scaffold.AppBar title="Settings" leading={<BackButton />} />
<Scaffold.Content scrollable={false}>
<FlatList data={sections} renderItem={renderSection} />
</Scaffold.Content>
</Scaffold>Full-bleed map
Turn off the content scroller when the child needs every available pixel and handles gestures itself. Screen chrome remains in its own regions.
<Scaffold>
<Scaffold.AppBar title="Choose a place" leading={<BackButton />} />
<Scaffold.Content scrollable={false}>
<MapView style={StyleSheet.absoluteFill} />
</Scaffold.Content>
<Scaffold.Footer>
<PlaceSummary />
<Button fullWidth>Use this place</Button>
</Scaffold.Footer>
</Scaffold>A base, not a fixed layout
Leave out any region the screen does not need. Scaffold coordinates safe areas and available space, but it does not force every screen to have a bar or footer.