AniUI Academy

StyleSheet and Styling Patterns

Why React Native uses StyleSheet.create instead of CSS, how unitless numbers work as density-independent pixels, and how to combine and conditionally apply styles.

8 min read

CSS on the web gives you cascading rules, selectors, and a browser engine that parses a stylesheet file. React Native has none of that. Styling here is plain JavaScript objects, validated and referenced through StyleSheet.create, using a unit system that isn't CSS's either. None of it is CSS wearing a disguise — it's worth understanding on its own terms.

StyleSheet.create is not a CSS parser

import { View, Text, StyleSheet } from "react-native";
 
function Card({ title }) {
  return (
    <View style={styles.card}>
      <Text style={styles.title}>{title}</Text>
    </View>
  );
}
 
const styles = StyleSheet.create({
  card: {
    backgroundColor: "#fff",
    borderRadius: 8,
    padding: 16,
  },
  title: {
    fontSize: 18,
    fontWeight: "600",
    color: "#111",
  },
});

styles.card and styles.title are plain JavaScript objects — a defined subset of style properties specific to React Native, not the full CSS property list, and not parsed from any stylesheet syntax. StyleSheet.create takes those objects and does two useful things with them: it validates that the properties you wrote are recognized style properties (catching typos like a misspelled property name at the point you define the style, rather than silently doing nothing), and it lets the resulting styles be referenced consistently by identity rather than recreated as brand-new objects on every single render — a small but real efficiency and correctness win compared to writing equivalent plain object literals inline everywhere.

You could, technically, skip StyleSheet.create and just use plain objects directly as style values — React Native will still apply them. StyleSheet.create is the established convention because of the validation and reference-stability benefits above, not because plain objects are actually forbidden.

Numbers are unitless — and that unit is not px

This is the detail that surprises people coming straight from CSS: React Native style numbers have no unit suffix at all.

const styles = StyleSheet.create({
  box: {
    width: 100,   // not "100px" — just the number 100
    height: 100,
    margin: 12,
  },
});

There's no px, no em, no rem — just a number. Those numbers are density-independent units: the platform scales them appropriately for the actual physical pixel density of the device's screen, so a width: 100 box reads as roughly the same physical size across devices with very different raw pixel densities, rather than 100 raw hardware pixels (which would look wildly different in physical size on a low-density screen versus a high-density one). This is conceptually close to what CSS's px unit is trying to approximate on the web (a CSS pixel is also not literally one hardware pixel on high-density displays) — but in React Native there's no unit keyword at all; a bare number is simply understood to mean this density-independent unit throughout the entire style system.

Percentages are supported as strings where it makes sense for a property (width: "50%"), but the plain-number case is the default you'll reach for constantly.

Combining styles: the array pattern

A single style object gets limiting fast once you need a base style plus situational variations. React Native's style prop accepts an array, and merges the objects in order — later entries win when properties conflict:

function Button({ label, selected }) {
  return (
    <View style={[styles.button, selected && styles.buttonSelected]}>
      <Text style={[styles.label, selected && styles.labelSelected]}>{label}</Text>
    </View>
  );
}
 
const styles = StyleSheet.create({
  button: {
    padding: 10,
    borderRadius: 6,
    backgroundColor: "#eee",
  },
  buttonSelected: {
    backgroundColor: "#3366ff",
  },
  label: {
    color: "#111",
  },
  labelSelected: {
    color: "#fff",
  },
});

selected && styles.buttonSelected evaluates to either the style object (when selected is true) or false (when it's not) — and React Native's array style form simply ignores falsy entries in the array, which makes this a very common, idiomatic way to express "apply this extra style conditionally."

Inline styles: fine when a value depends on data

StyleSheet.create styles are defined once, ahead of time — they can't depend on a specific prop value at render time (like an exact color computed from a piece of data). For that, a plain inline style object is the right, ordinary tool, usually combined with a StyleSheet.create base via the array pattern:

function ProgressBar({ percent }) {
  return (
    <View style={styles.track}>
      <View style={[styles.fill, { width: `${percent}%` }]} />
    </View>
  );
}
 
const styles = StyleSheet.create({
  track: {
    height: 8,
    borderRadius: 4,
    backgroundColor: "#eee",
    overflow: "hidden",
  },
  fill: {
    height: 8,
    backgroundColor: "#3366ff",
  },
});

Here, styles.fill covers everything static about the bar's fill, and the inline { width: `${percent}%` } covers the one property that genuinely depends on a prop. Reaching for an inline object isn't a shortcut you should feel bad about — it's the correct tool specifically when a style value can't be known ahead of time.

What to remember

  • StyleSheet.create validates plain JS style objects and lets them be referenced efficiently — it is not a CSS parser, and the properties it accepts are a defined RN-specific subset, not full CSS.
  • Style numbers are unitless density-independent units, not CSS px — there is no unit suffix at all.
  • The array form of style merges styles in order, with later entries overriding conflicting properties from earlier ones — the standard pattern for conditional styling.
  • Falsy entries (like false from a && expression) in a style array are simply ignored, which is why selected && styles.selected is idiomatic.
  • Inline style objects are the right tool when a value depends on props or state at render time; StyleSheet.create styles are for everything static.

Check yourself

3 questions · pass 3/3 to unlock ScrollView vs. FlatList

up to 50
  1. 1.What kind of thing does StyleSheet.create actually work with?

  2. 2.In style={{ width: 100 }}, what does the number 100 represent?

  3. 3.What does style={[styles.a, styles.b]} do, and why is this pattern useful?

3 left to answer