In React Native, where views default to position relative, how does an absolutely positioned badge find its anchor, and what does position: 'static' change?
answer
- every view is relative by default
- absolute leaves the normal flow
- insets measured from the containing block
- static ignores insets, forms no block
- a transform also makes a block
basics
~20 sAn absolute view's insets are measured from its containing block: the nearest ancestor that is not position: 'static' or has a transform. Views default to relative, so that is usually the parent; 'static' ignores insets and lets absolute children skip past it.
solid answer
~50 sIn React Native every view is `position: 'relative'` by default: it sits in the normal flex flow and `top`, `left` and the other insets merely nudge it without moving siblings. A `position: 'absolute'` view leaves the flow, so siblings lay out as if it were absent, and its insets are measured from its **containing block**: the nearest ancestor whose position is not `static`, or that has a `transform`. Because every view is relative unless told otherwise, that is normally the direct parent, so a "Most popular" badge anchors to its own card. `position: 'static'` keeps a view in the flow, ignores its insets, and stops it forming a containing block, so an absolute child inside it anchors to an ancestor further up. It arrived in 0.74 with Yoga 3.0 on the New Architecture, which since 0.82 is the only architecture.
code
tsx · 26 linesimport type { ReactNode } from 'react';
import { StyleSheet, Text, View } from 'react-native';
export function PlanCard({ children }: { children: ReactNode }) {
return (
<View style={styles.card}>
<View style={styles.body}>
{children}
<Text style={styles.badge}>Most popular</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
card: { borderWidth: 1, borderRadius: 8, padding: 4 },
body: { position: 'static', padding: 16 },
badge: {
position: 'absolute',
top: -10,
right: 12,
paddingHorizontal: 8,
backgroundColor: '#1f6feb',
color: '#ffffff',
},
});go deeper
Recall that every view is relative by default, so an absolute child is measured from its parent.
Explain the containing-block rule: nearest ancestor that is not static or has a transform, plus what static does to insets and to absolute descendants.
Use static and transforms deliberately in shared components so consumers' overlays anchor where the design expects, and review draw order and zIndex for overlaps.
Decide how a component library exposes overlay slots, such as badges and ribbons, so product code never depends on the library's internal wrapper structure.
## Three position types React Native's `position` style accepts `'relative'`, `'absolute'` and `'static'`, and **Yoga**, the engine that lays out every view, handles each differently. | Value | In normal flow | Insets (`top`, `right`, `bottom`, `left`) | Forms a containing block for absolute descendants | |---|---|---|---| | `relative` (default) | Yes | Offset the view from its laid-out spot, without moving siblings | Yes | | `absolute` | No, siblings ignore it | Measured from its containing block | Yes | | `static` | Yes | Ignored | No, unless it has a `transform` | The default matters most: **every view is `relative` unless its style says otherwise**. That single fact makes absolute positioning in React Native local and predictable. ## How an absolute view finds its anchor The **containing block** is the ancestor whose box an absolute view's insets and percentages are measured against. The rules are short: 1. If a view is `relative` or `static`, its containing block is its parent. 2. If a view is `absolute`, its containing block is the nearest ancestor that either has a position other than `static`, or has a `transform`. Since ancestors are `relative` by default, rule 2 almost always stops at the **direct parent**. Percentages on an absolute view, such as `width: '50%'`, are also resolved against its containing block. ## The pricing-card badge A "Most popular" badge should overlap the top edge of one plan card: - Give the badge `position: 'absolute'`, `top: -10` and `right: 12`. - Do nothing to the card: it is already `relative`, so the badge is measured from the card. - Because the badge left the flow, the card's title and price lay out as if the badge were not there; add padding to the card if the badge must not cover them. - Draw order follows the tree: later siblings paint over earlier ones, so place the badge after the content, or raise it with `zIndex` if it must sit above a later sibling. ## What static is for Sometimes the badge's JSX parent is not the view it should anchor to. A design system's card might render your children inside an inner padded wrapper, and you want the badge at the **outer** card's corner. Setting `position: 'static'` on the inner wrapper does exactly that: - The wrapper stays in the flow and keeps its size and padding. - Its own insets are ignored, so `top` on the wrapper has no effect. - It no longer forms a containing block, so the badge skips it and anchors to the outer card. - A `transform` on the wrapper would make it a containing block again, even with `static`. `position: 'static'` was introduced in React Native 0.74 with Yoga 3.0 and only on the New Architecture. Since 0.82 the New Architecture is the only architecture, so on 0.87 it is always available. ## Common mistakes - Expecting an absolute child to anchor to the screen, as it would under an unpositioned ancestor on the web. In React Native it anchors to its parent. - Wrapping content in an extra `View` to "create" a positioning context, when every `View` already is one. - Using `static` to try to make a header stick while scrolling; `static` has nothing to do with scrolling. - Forgetting that insets on a `relative` view offset only that view: moving it with `top: 8` leaves a gap where it was, because siblings still use its original spot. ## Overlays and the inset shorthand For a dimmed overlay across a whole card or screen, the usual pattern is an absolute view with all four insets at 0 inside the view it should cover. The `inset` style sets `top`, `right`, `bottom` and `left` in one go, so `{ position: 'absolute', inset: 0 }` covers the containing block exactly. Because the overlay's containing block is its parent by default, the same overlay component covers a single card when placed inside a card and the whole screen when placed inside the screen's root view, with no change to its styles. Percentages behave the same way: `width: '50%'` on an absolute view is half of the containing block, whatever its parent's own content size.
- Does an absolutely positioned view still affect its siblings' layout?No. An absolute view is taken out of the flow, so its siblings lay out as if it did not exist, and it takes no space in the parent's main-axis sizing. That is why an overlapping badge can cover a card's title: add padding or margin to the content if the badge must not overlap it.
- What makes a static wrapper form a containing block again?A `transform`. The containing-block rule for an absolute view looks for the nearest ancestor with a position other than `static` or with a `transform`, so a `static` wrapper that also has, say, `transform: [{ scale: 1 }]` captures the absolute child again.
saying these in an interview costs you the question
- Views are position static by default, as elements are on the web.
- An absolute child is positioned relative to the screen unless you add a relative wrapper.
- position: 'static' pins a view in place while its ScrollView scrolls.
- Moving a relative view with top: 8 pushes its siblings down.
- React Native supports only relative and absolute positioning.