Container
A centred Column with a maximum width. Below that width it fills its parent, so a phone sees no change. On a tablet or a browser window the content stops at the width you name and sits in the middle.
Use it as the one child of a ScrollView, with the screen padding on it. Every screen then shares one content column, and no screen writes its own maxWidth.
Usage
import { Container, Typography } from '@rootnative/components'
import { mdiResolver } from '@rootnative/components/mdi'
import { ThemeProvider } from '@rootnative/core'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import { ScrollView } from 'react-native'
export default function App() {
return (
<SafeAreaProvider>
<ThemeProvider iconResolver={mdiResolver}>
<ScrollView>
<Container p="lg" gap="md">
<Typography variant="headlineSmall">Settings</Typography>
<Typography variant="bodyMedium">
This column is at most 600dp wide and sits in the middle of a
wide window. On a phone it fills the screen.
</Typography>
</Container>
</ScrollView>
</ThemeProvider>
</SafeAreaProvider>
)
}
Widths
The width prop names a breakpoint band. The Container grows to the lower bound of that band and no further. The limit includes the padding.
width | Maximum width | Use for |
|---|---|---|
medium (default) | 600dp | Reading content, forms, a settings list |
expanded | 840dp | A list with a detail pane, a wide form |
large | 1200dp | A dashboard, a card grid |
extraLarge | 1600dp | A full-width canvas with margins |
<ScrollView>
<Container width="large" p="lg">
<Grid columns={{ compact: 1, medium: 2, expanded: 4 }} gap="md">
{cards}
</Grid>
</Container>
</ScrollView>
The values are the same as the breakpoints export of @rootnative/core, so a Grid inside a Container changes its column count at the same widths the Container stops growing.
Padding goes on the Container
Put the screen padding on the Container, not on the ScrollView. The limit then applies to the padded box, and the content column lines up from screen to screen.
// Both screens show their text at the same x on a wide window.
<ScrollView>
<Container p="lg" gap="xl">
<Typography variant="headlineSmall">First screen</Typography>
</Container>
</ScrollView>
<ScrollView>
<Container p="lg" gap="xl">
<Typography variant="headlineSmall">Second screen</Typography>
</Container>
</ScrollView>
A style prop wins over the width rule, so style={{ maxWidth: 400 }} narrows one screen without a new band.
Props
| Prop | Type | Default | Required | Description |
|---|---|---|---|---|
width | enum | medium | No | The widest the Container grows, padding included. Below that width it fills its parent. |
inverted | boolean | false | No | Reverses the layout direction (`column-reverse`). |
p | SpacingValue | - | No | Padding on all sides |
px | SpacingValue | - | No | Horizontal padding (paddingStart + paddingEnd) |
py | SpacingValue | - | No | Vertical padding (paddingTop + paddingBottom) |
pt | SpacingValue | - | No | Padding top |
pb | SpacingValue | - | No | Padding bottom |
ps | SpacingValue | - | No | Padding start (left in LTR, right in RTL) |
pe | SpacingValue | - | No | Padding end (right in LTR, left in RTL) |
m | SpacingValue | - | No | Margin on all sides |
mx | SpacingValue | - | No | Horizontal margin (marginStart + marginEnd) |
my | SpacingValue | - | No | Vertical margin (marginTop + marginBottom) |
mt | SpacingValue | - | No | Margin top |
mb | SpacingValue | - | No | Margin bottom |
ms | SpacingValue | - | No | Margin start |
me | SpacingValue | - | No | Margin end |
gap | SpacingValue | - | No | Gap between children |
rowGap | SpacingValue | - | No | Row gap between children |
columnGap | SpacingValue | - | No | Column gap between children |
flex | number | - | No | Flex value |
align | enum | - | No | Align items along the cross axis |
justify | enum | - | No | Justify content along the main axis |
bg | string | - | No | Background color |
hrefAttrs | { target?: string; rel?: string; download?: string | boolean; } | - | No | Web only. The `target`, `rel` and `download` of the `<a>` that a view with an `href` renders, for example under Expo Router's `<Link asChild>`. `target: '_blank'` opens the link in a new tab. Native ignores it. |
onKeyDown | (event: { nativeEvent: { key?: string; }; }) => void | - | No | - |