In React Native, which Yoga flexbox defaults differ from CSS, and why does a two-column pricing layout ported from the web stack vertically?
answer
- the property you did not write
- flexDirection defaults to column
- flexShrink defaults to 0, not 1
- flex is one number, not a shorthand
- alignContent flex-start, position relative
basics
~20 sYoga defaults flexDirection to column, flexShrink to 0, alignContent to flex-start and position to relative, and takes flex as a single number. A ported row of plan cards therefore stacks vertically until its container sets flexDirection: 'row'.
solid answer
~40 sReact Native lays out every `View` with **Yoga**, which implements flexbox but with different defaults. `flexDirection` is `column`, so children stack top to bottom unless the container says `flexDirection: 'row'`. `flexShrink` is `0`, so items keep their size and overflow instead of squeezing to fit. `flex` accepts one number, not the `'1 1 auto'` shorthand, and a positive value means grow in that proportion from a zero basis. `alignContent` defaults to `flex-start`, and every view is `position: 'relative'`, so an absolute child anchors to its parent. `alignItems: 'stretch'` and `justifyContent: 'flex-start'` stay the same. So the two pricing cards stack because nobody set the row direction, and any long content in them overflows because nothing shrinks by default.
code
tsx · 22 linesimport { StyleSheet, Text, View } from 'react-native';
export function PricingRow() {
return (
<View style={styles.row}>
<View style={styles.card}>
<Text style={styles.title}>Monthly</Text>
<Text>Billed every month, cancel anytime.</Text>
</View>
<View style={styles.card}>
<Text style={styles.title}>Yearly</Text>
<Text>Two months free when billed once a year.</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
row: { flexDirection: 'row', gap: 12, padding: 16 },
card: { flex: 1, padding: 16, borderWidth: 1, borderRadius: 8 },
title: { fontWeight: '600', marginBottom: 4 },
});go deeper
Recall the column default first, then flexShrink 0 and flex as a number. Show the one-line fix: flexDirection: 'row' on the container that should be a row.
Walk the full list of differing defaults and what each one does to a ported layout, including the ones that stay the same, such as alignItems stretch and justifyContent flex-start.
Treat a web-to-mobile port as a checklist: container directions, which items may shrink, shorthand flex values, units and positioning anchors. Explain how you would review a shared component library for these assumptions.
Weigh whether shared layout code between web and React Native is worth it given different defaults, and where a single flexbox mental model breaks down for a team moving between both.
## Why React Native has its own flexbox React Native does not run a browser engine. Every `View` becomes a native view, and its size and position are computed by **Yoga**, a cross-platform layout engine written in C++ that implements the flexbox model. Yoga follows the flexbox rules closely, but React Native runs it with **different defaults**, and there is no cascade or browser stylesheet sitting on top: the layout props in a style object are the entire input. That is why a layout copied from a web page can look broken even though every property name is familiar. The property you *did not write* still has a value, and on React Native that value is often different. ## The defaults that differ | Property | Web default | React Native (Yoga) default | Visible effect | |---|---|---|---| | `flexDirection` | `row` | `column` | Children stack top to bottom | | `flexShrink` | `1` | `0` | Items keep their size and overflow instead of shrinking | | `flex` | a grow/shrink/basis shorthand | a single number | `flex: 1` means grow from a zero basis; strings are rejected by the type | | `alignContent` | `stretch` | `flex-start` | Wrapped lines pack at the start | | `position` | `static` | `relative` | An absolute child anchors to its parent | | `boxSizing` | `content-box` | `border-box` | `width` already includes padding and border | | `display` | `block` for most elements | `flex` | Every `View` is already a flex container | Two defaults do **not** differ, which is worth saying so you do not over-correct: - `alignItems` is `stretch`, so children fill the cross axis unless told otherwise. - `justifyContent` is `flex-start`, so children pack at the start of the main axis. ## Porting a two-column pricing layout Suppose the web version is a container with `display: flex`, two plan cards with `flex: 1`, and `gap` between them. Pasted into React Native as style objects: 1. The container is already a flex container, so `display: 'flex'` changes nothing. Its direction is `column`, though, so the "Monthly" and "Yearly" cards stack vertically. Add `flexDirection: 'row'` to the container. 2. `flex: 1` on each card still works because it is a number: each card grows in proportion 1 from a basis of 0, so the two split the row equally. 3. If a card used a shorthand such as `flex: '1 1 300px'`, rewrite it as separate numeric `flexGrow`, `flexShrink` and `flexBasis` values. The `flex` style is typed as `number`, and a string is not parsed as a shorthand. 4. `gap: 12` works (flex gap arrived in React Native 0.71). Lengths are unitless density-independent points or percentage strings; `px`, `rem` and viewport units do not exist. 5. Content that relied on shrinking to fit, such as a long feature line beside a check icon, now needs an explicit `flexShrink: 1`, because nothing shrinks by default. ```tsx const styles = StyleSheet.create({ row: { flexDirection: 'row', gap: 12, padding: 16 }, card: { flex: 1, padding: 16, borderWidth: 1, borderRadius: 8 }, }); ``` ## How the column default shapes everyday screens Because the direction is `column` and `alignItems` is `stretch`, a plain `View` with a few children behaves like a vertical stack of full-width blocks. A form, a settings screen or a card body needs no layout code at all. The cost falls on anyone who expects a horizontal row: they must ask for it, on every container that should be one. The same habit applies to shrinking: in React Native you opt **into** shrinking on the item that should give way, rather than opting out on the item that should not. ## Traps when reading a layout bug - **Assuming items shrink**: a row of feature chips wider than the screen does not squeeze; the last chips run past the edge. - **Web units**: `'10px'`, `'2rem'` and `'50vw'` are not valid lengths; use numbers or `'50%'`. - **Web positioning habits**: an absolutely positioned "Most popular" badge anchors to its own card, because the card is `relative` by default, not to some distant positioned ancestor. - **Shorthand strings**: `flex: '1'` is a TypeScript error because the style type is a number. - **Media queries**: a style object has none; responsive layout comes from flex, wrapping, percentages and window dimensions read in code. - **Cascade**: a parent `View`'s layout props never flow down to its children; each view is laid out only from its own style and its parent's container props. Knowing these defaults turns most "the web layout collapsed" bugs into a one-line fix on the right container or item.
- Does alignItems also default differently in React Native?No. `alignItems` defaults to `stretch` as on the web, so in the default `column` direction every child stretches to the container's full width. That is why a ported card that looked content-sized on the web suddenly fills the screen horizontally: stretch is acting on the cross axis, which is now horizontal.
- What happens if a React Native style sets flex: '1 1 auto' copied from CSS?React Native's `flex` style is typed as a single `number`, so TypeScript rejects the string, and it is not expanded into grow, shrink and basis. Write the three longhands instead: `flexGrow: 1`, `flexShrink: 1` and leave `flexBasis` at its `auto` default, or set it to a number or percentage.
- How do you space the two pricing cards without margins on the outer edges?Use `gap` (or `columnGap` and `rowGap`) on the container. It puts space only between children, never before the first or after the last, so the cards need no `marginRight` with a special case for the last one. React Native has supported flex gap since 0.71.
saying these in an interview costs you the question
- React Native uses row as the default flexDirection, like CSS.
- Flex items shrink by default, so a row can never overflow.
- The flex style accepts a CSS shorthand string such as '1 1 auto'.
- Views are position static by default, so absolute children anchor far up the tree.
- Wrapped lines stretch to fill the container because alignContent defaults to stretch.
- Lengths accept px, rem or vw units the same way CSS does.