Screen Layout Patterns
This document describes the standardized layout components and patterns for building consistent screens in Sanctiv.Overview
All screens should use the layout components from the design system (../design-system/components). These components handle:
- Safe area insets automatically
- Tab bar offsets for screens inside tab navigator
- Keyboard avoiding behavior
- Consistent header styling
Screen Placement Standard
Critical Decision: Where should screens live in the navigation hierarchy?The Rule
| Screen Type | Placement | Route Example |
|---|---|---|
| Tab root (list/browse) | Inside tabs | /(tabs)/companions |
| Detail views | Inside tabs | /(tabs)/companions/[id] |
| Contextual screens (chat) | Inside tabs | /(tabs)/companions/chat/[id] |
| Create forms | Outside tabs | /companions/add |
| Edit forms | Outside tabs | /companions/edit/[id] |
| Global features | Outside tabs | /profile, /guided-journal |
Why This Standard?
- Clean tab bar behavior - No workarounds needed to hide tab bar
- Consistent UX - All forms look identical (full-screen, ActionBottomBar)
- Simpler code - No conditional tab bar hiding logic
- Industry best practice - Follows Apple HIG for focused tasks
Decision Tree: Inside or Outside Tabs?
Current Route Structure
Examples
Import Path Patterns: This project uses theCreate Form (Outside Tabs):@/path alias (configured inapps/mobile/tsconfig.json→@/*maps tosrc/*). Route files inapp/typically use the alias (@/screens,@/components), while component examples in this doc use relative paths (../design-system/components) for clarity. Prefer the alias when available; use relative paths when the alias isn’t accessible or when documenting component relationships.
Components
ScreenContainer
The foundation wrapper for all screens. Handles SafeAreaView, KeyboardAvoidingView, and tab bar offsets.| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'default' | 'tab' | 'modal' | 'default' | Screen context for safe area/offset handling |
keyboardAvoiding | boolean | false | Enable KeyboardAvoidingView |
backgroundColor | string | colors.neutral.white | Background color |
testID | string | - | Test identifier |
ScreenHeader
Standardized header following Apple Human Interface Guidelines.| Prop | Type | Default | Description |
|---|---|---|---|
title | string | Required | Screen title (centered) |
variant | 'back' | 'close' | 'none' | 'back' | Left navigation variant |
onBack | () => void | - | Required for ‘back’/‘close’ variants |
rightAction | ReactNode | - | Optional right-side element |
subtitle | string | - | Optional subtitle below title |
showBorder | boolean | true | Show bottom border |
ActionBottomBar
Fixed bottom action bar for forms and primary actions.| Prop | Type | Default | Description |
|---|---|---|---|
onAction | () => void | Required | Primary action callback |
actionLabel | string | 'Save' | Primary button label |
onCancel | () => void | - | Cancel button callback |
cancelLabel | string | 'Cancel' | Cancel button label |
variant | 'default' | 'tab' | 'default' | Adds tab bar offset |
isLoading | boolean | false | Show loading state |
isActionDisabled | boolean | false | Disable primary button |
showCancel | boolean | true | Show cancel button |
Layout Constants
Centralized layout values inconstants/layout.ts:
Preferred (path alias):
Note: Prefer the path alias@/constants/layoutwhen available. Use relative paths (../or../../) only when the alias is not configured or not accessible from your file location.
| Constant | Value | Description |
|---|---|---|
TAB_BAR_HEIGHT | 49 | iOS tab bar height |
HEADER_HEIGHT | 56 | Standard header height |
ACTION_BAR_HEIGHT | 88 | ActionBottomBar height |
MIN_TOUCH_TARGET | 44 | Apple HIG minimum (44pt) |
CONTENT_PADDING | 16 | Standard horizontal padding |
CONTENT_PADDING_WITH_ACTION_BAR | 120 | Padding when action bar present |
CONTENT_PADDING_WITH_TAB_AND_ACTION_BAR | 169 | Padding for tab + action bar |
Patterns
Tab Root Screen
Tab root screens typically have custom headers with actions:Form Screen (Outside Tabs - Recommended)
Forms should be placed outside tabs for clean, focused experience:Note: See Screen Placement Standard for why forms should be outside tabs.
Modal Screen
Full-screen modals:Chat Screen (Custom Header)
Some screens need custom headers for unique requirements:Decision Tree: Which Variant?
First: Determine if screen should be inside or outside tabs. See Screen Placement Standard.
Migration Guide
When migrating existing screens:- Replace
SafeAreaViewwithScreenContainer - Replace custom header
ViewwithScreenHeader - Remove manual
useSafeAreaInsetsandpaddingTopcalculations - Remove manual
TAB_BAR_HEIGHTcalculations (usevariant="tab"instead) - Replace inline styles with
StyleSheet.create() - Use design tokens from
../design-system/tokens