Skip to content

SettingsLayout

A layout shell that combines a TopNavBar with a scrollable content area. Use for settings screens, detail screens, and any screen that needs a nav bar + vertically scrolling content.

When to use: Settings screens, profile screens, detail/info screens, any screen navigated into from a deeper level.

When not to use: Auth screens — use AuthLayout. Screens with custom fixed headers or special navigation structures.

import { SettingsLayout } from '@/components';
<SettingsLayout title="Settings" onBack={router.back}>
<SettingsGroup title="Account" rows={accountRows} />
<SettingsGroup title="Notifications" rows={notificationRows} />
</SettingsLayout>
PropTypeDefaultDescription
titlestringNav bar title (required)
onBack() => voidBack action; renders back button when set
rightActionsArray<{ icon, onPress, accessibilityLabel }>[]Right nav bar actions (up to 2)
childrenReactNodeScrollable content (required)
footerReactNodeFixed bottom element (e.g. save button)
testIDstring
┌──────────────────────────────────┐
│ [back] [title] [actions] │ TopNavBar
├──────────────────────────────────┤
│ │
│ [children] │ ScrollView
│ (SettingsGroups, etc.) │
│ │
├──────────────────────────────────┤
│ [footer] │ Fixed bottom (optional)
└──────────────────────────────────┘
export function AccountSettingsScreen() {
const [push, setPush] = useState(true);
return (
<SettingsLayout title="Account" onBack={router.back}>
<SettingsGroup
title="Profile"
rows={[
{ label: 'Display Name', rightAccessory: 'value', value: 'Sarah Chen', onPress: editName },
{ label: 'Email', rightAccessory: 'value', value: 'sarah@example.com', onPress: editEmail },
]}
/>
<SettingsGroup
title="Notifications"
rows={[
{ label: 'Push alerts', rightAccessory: 'switch', checked: push, onToggle: setPush },
]}
/>
</SettingsLayout>
);
}
<SettingsLayout
title="Edit Profile"
onBack={router.back}
footer={
<View style={{ padding: 16 }}>
<Button variant="primary" onPress={saveProfile} isLoading={isSaving}>
Save changes
</Button>
</View>
}
>
<FormField label="Display name" value={name} onChangeText={setName} />
<FormField label="Bio" value={bio} onChangeText={setBio} />
</SettingsLayout>
<SettingsLayout
title="Notifications"
onBack={router.back}
rightActions={[
{ icon: CheckCircle, onPress: markAllRead, accessibilityLabel: 'Mark all as read' },
]}
>
<ListSection items={notifications} />
</SettingsLayout>

Do: Place SettingsGroup and ListSection organisms directly in children — they handle their own spacing.

Don’t: Wrap children in unnecessary containers. The layout adds padding automatically.