In React Native 0.87, what do StyleSheet.absoluteFill and StyleSheet.hairlineWidth provide, and what replaced StyleSheet.absoluteFillObject?
answer
- absolute plus four zero edges
- absoluteFillObject gone in 0.85
- spread it inside create
- a whole number of physical pixels
- not a constant across densities
basics
~20 sStyleSheet.absoluteFill is a ready-made style that pins a view to all four edges of its parent; absoluteFillObject was removed in 0.85 in its favour. StyleSheet.hairlineWidth is the platform's thin-line width, rounded to whole physical pixels.
solid answer
~40 s`StyleSheet.absoluteFill` is the object `{ position: 'absolute', left: 0, right: 0, top: 0, bottom: 0 }`, frozen in development. It is the usual way to lay an overlay - a "USED" stamp over a redeemed coupon - across its parent, either as an array entry or spread into a named style with `...StyleSheet.absoluteFill`. `StyleSheet.absoluteFillObject` was the same shape; it was deprecated in 0.82 and **removed in 0.85**, so on 0.87 and on Expo SDK 57 (0.86) code must use `absoluteFill`. `StyleSheet.hairlineWidth` is for the thinnest crisp line, such as a coupon's tear-off divider. It is computed as `PixelRatio.roundToNearestPixel(0.4)`, falling back to one physical pixel when that rounds to zero - so it is always a whole number of physical pixels, usually one, but not a fixed number of points.
code
tsx · 31 linesimport { StyleSheet, Text, View } from 'react-native';
export function RedeemedCoupon({ title }: { title: string }) {
return (
<View style={styles.card}>
<Text style={styles.title}>{title}</Text>
<View style={styles.divider} />
<Text>Valid in store only</Text>
<View style={styles.stamp}>
<Text style={styles.stampText}>USED</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
card: { padding: 16, borderRadius: 12, backgroundColor: '#ffffff' },
title: { fontSize: 18, fontWeight: '600' },
divider: {
height: StyleSheet.hairlineWidth, // crisp: a whole number of physical pixels
backgroundColor: '#c8c8c8',
marginVertical: 12,
},
stamp: {
...StyleSheet.absoluteFill, // was absoluteFillObject before React Native 0.85
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'rgba(255,255,255,0.7)',
},
stampText: { fontSize: 28, fontWeight: '800', color: '#9a2f2f' },
});go deeper
Know that absoluteFill pins a view to its parent's edges and that hairlineWidth is the thin line width for dividers and borders.
Explain how hairlineWidth is computed from the pixel ratio, why it is not a constant, and that absoluteFillObject was removed in 0.85.
Catch upgrade breakage from removed StyleSheet members, avoid hard-coded half-point borders, and keep hairline values out of layout arithmetic.
Fold removed-API cleanups like absoluteFillObject into a regular upgrade cadence so a React Native bump does not stall on scattered style references.
## StyleSheet's two properties Besides its functions (`create`, `flatten`, `compose`), React Native's `StyleSheet` exposes two ready-made values. Both exist to remove a small, error-prone repetition from everyday styling. ## absoluteFill `StyleSheet.absoluteFill` is a style object with five properties: | Property | Value | |---|---| | `position` | `'absolute'` | | `left` | `0` | | `right` | `0` | | `top` | `0` | | `bottom` | `0` | Applied to a child, it stretches that child over its parent's box. In a coupon wallet, a redeemed coupon keeps its card and adds a semi-transparent "USED" stamp on top: - **As an array entry:** `style={[StyleSheet.absoluteFill, styles.stamp]}`, with the stamp's colour and alignment in `styles.stamp`. - **Spread into a named style:** `stamp: { ...StyleSheet.absoluteFill, backgroundColor: 'rgba(255,255,255,0.7)' }` inside `StyleSheet.create`, which the docs mention as a way to build a customised entry. In development the object is **frozen**, so code cannot mutate the shared overlay style by accident; build variations by adding entries or spreading, never by assigning to it. ### What happened to absoluteFillObject Older code used `StyleSheet.absoluteFillObject`, which had the same five properties. It was **deprecated in React Native 0.82** in favour of the equivalent `absoluteFill`, and **removed in 0.85**; the 0.85 release post shows the one-line migration. On React Native 0.87 - and on Expo SDK 57, which runs 0.86 - `StyleSheet.absoluteFillObject` no longer exists, so any reference to it is a type error and `undefined` at runtime. ## hairlineWidth `StyleSheet.hairlineWidth` is "the width of a thin line on the platform" - the value to use for a divider or a light border, such as the dashed-looking separator between a coupon's stub and its body. The 0.87 implementation computes it once, lazily: 1. Take `PixelRatio.roundToNearestPixel(0.4)`, which rounds 0.4 points to the nearest whole number of physical pixels and converts back to points. 2. If that rounds to `0` - on a screen with a pixel ratio of 1 - use `1 / PixelRatio.get()` instead, which is one physical pixel. The result is always a **whole number of physical pixels**, so the line renders crisply rather than blurred across two pixel rows. Worked through for common pixel ratios: | Pixel ratio | 0.4 pt in pixels | Rounded | `hairlineWidth` in points | |---|---|---|---| | 1 | 0.4 | 0, so fallback | 1 | | 2 | 0.8 | 1 | 0.5 | | 3 | 1.2 | 1 | about 0.333 | | 4 | 1.6 | 2 | 0.5 | So it is **usually one physical pixel, but not always** - at a pixel ratio of 4 it is two - and its value in points differs by device. The docs say exactly that: it will try to match the standard thin line of the platform, but you should not rely on it being a constant size. They add that a hairline may not be visible at all on a downscaled simulator. ## Two ways to use a hairline - **As a border:** `borderBottomWidth: StyleSheet.hairlineWidth` on a row, the docs' own example, draws a separator along the row's edge. - **As a height:** a dedicated divider `View` with `height: StyleSheet.hairlineWidth` and a background colour, which is easier to inset with margins and to hide conditionally. Either way, the value is read once and cached, so referencing it in `StyleSheet.create` at module scope costs nothing per render. ## Pitfalls - **Using hairlineWidth for layout arithmetic.** Because its point value varies by device, do not use it to compute offsets that must line up exactly with other elements. - **Hard-coding `borderWidth: 1` for a hairline.** One point is three physical pixels at a ratio of 3, visibly heavier than the platform's thin line. - **Assuming absoluteFill covers the screen.** It fills the **parent's** box, not the window. - **Keeping absoluteFillObject behind a compatibility shim.** It was removed; replace it.
- Why is StyleSheet.hairlineWidth two physical pixels on some Android devices?Because it is computed as `PixelRatio.roundToNearestPixel(0.4)`. At a pixel ratio of 4, 0.4 points is 1.6 pixels, which rounds to 2, giving 0.5 points. Only when the rounding reaches zero does it fall back to exactly one physical pixel. The docs warn not to rely on it being a constant size for that reason.
- After an upgrade, a redeemed coupon's overlay loses its positioning where it spread StyleSheet.absoluteFillObject. What changed?`absoluteFillObject` was deprecated in React Native 0.82 and removed in 0.85, so on 0.87 it is `undefined`. Spreading `undefined` into an object literal is harmless in JavaScript, so the overlay silently loses its positioning - or TypeScript flags the missing property. Replace it with `StyleSheet.absoluteFill`, which has the same five properties.
saying these in an interview costs you the question
- StyleSheet.hairlineWidth is always exactly one physical pixel.
- StyleSheet.hairlineWidth is a fixed 0.5 points on every device.
- StyleSheet.absoluteFillObject is still the recommended overlay style in 0.87.
- StyleSheet.absoluteFill stretches a view over the whole screen.
- You can adjust StyleSheet.absoluteFill by assigning new values to it.