Styling with StyleSheet
React Native has no CSS files at all. There is no .css, no
stylesheet link, no cascade, and no selectors like .className or #id.
Every single style in a React Native app is a plain JavaScript object — a set
of key/value pairs that describe how a component should look, passed to that component through
its style prop. Once you internalize that one fact, styling in React Native stops
feeling mysterious: it's "CSS-like" in the property names it borrows, but it is JavaScript,
through and through.
StyleSheet.create — The Standard Way to Define Styles
You could write styles as a plain object literal directly in your component, and it
would work. But the idiomatic, recommended approach is StyleSheet.create({...})
from the react-native package:
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
export default function Greeting() {
return (
<View style={styles.container}>
<Text style={styles.title}>Hello, React Native!</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: '#ffffff',
},
title: {
fontSize: 22,
fontWeight: 'bold',
color: '#222222',
},
});
Why bother with StyleSheet.create instead of just writing
const styles = { container: { flex: 1, ... } } as a plain object? Two practical
reasons:
| Reason | What it means |
|---|---|
| Performance | Under the hood, StyleSheet.create can convert each style object into a numeric ID. Instead of sending the whole style object across the JS-to-native bridge on every render, React Native can send just that ID, which is cheaper for repeated renders. |
| Validation & tooling | Because StyleSheet.create knows it's dealing with style objects, editors and linters can validate property names and give you autocomplete, and React Native can warn you about invalid style properties at development time. |
| Convention & readability | Keeping all your styles in one StyleSheet.create({...}) block at the bottom of the file (by convention) keeps your JSX clean and your styles easy to scan in one place. |
StyleSheet.create. But it's the standard, idiomatic approach used in essentially every real React Native codebase, so it's what you should reach for by default.Applying a Style to a Component
Every core component accepts a style prop. You apply a style object by referencing
it from your styles object:
<View style={styles.container}>
<Text style={styles.title}>Dashboard</Text>
</View>
Note the curly braces: style={styles.container} is a JavaScript expression (a
reference to an object), not a string — this is standard JSX, exactly like passing any other
prop that isn't a plain string.
A Full Worked Example: A Simple Profile Card
Here's a complete example defining and applying several styles together, to see how it all fits into one component:
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
export default function ProfileCard() {
return (
<View style={styles.card}>
<Text style={styles.name}>Sonu Kumar Pandit</Text>
<Text style={styles.role}>React Native Developer</Text>
</View>
);
}
const styles = StyleSheet.create({
card: {
backgroundColor: '#f2f6ff',
borderRadius: 12,
padding: 16,
margin: 12,
},
name: {
fontSize: 18,
fontWeight: '600',
color: '#1a1a1a',
},
role: {
fontSize: 14,
color: '#666666',
marginTop: 4,
},
});
Combining Multiple Styles With an Array
Sometimes a component needs more than one style object at once — a base style plus a modifier.
React Native's style prop accepts an array of style objects, and
it merges them in order:
<View style={[styles.box, styles.shadow]}>
<Text>Card with a shadow</Text>
</View>
// styles.box and styles.shadow are merged left to right
const styles = StyleSheet.create({
box: {
padding: 16,
backgroundColor: '#ffffff',
borderRadius: 8,
},
shadow: {
shadowColor: '#000',
shadowOpacity: 0.2,
shadowRadius: 6,
elevation: 4,
},
});
The important rule: when two styles in the array set the same property, the later one in the array wins. This is how you implement conditional or "modifier" styles — start with a base style, then conditionally append an override:
<View style={[styles.box, isActive && styles.activeBox]}>
<Text>Toggle me</Text>
</View>
// styles.activeBox overrides any matching properties in styles.box, but only when isActive is true
const styles = StyleSheet.create({
box: { backgroundColor: '#eeeeee', padding: 14 },
activeBox: { backgroundColor: '#c8f7c5' },
});
Inline Styles for One-Off Dynamic Values
Not every style value is known ahead of time. When a style genuinely depends on runtime data — an opacity that changes with state, a width computed from a measurement — an inline style object written directly in JSX is perfectly fine:
<View style={{ opacity: isVisible ? 1 : 0 }}>
<Text>Fades based on state</Text>
</View>
Notice the double curly braces: the outer {} is the normal JSX "this is JavaScript"
escape, and the inner {} is the plain object literal being written on the spot.
StyleSheet.create for anything static or reused across renders. Reach for an inline object only for values that are genuinely computed at render time and specific to that one instance — otherwise you lose the performance and tooling benefits described above.Common Style Properties Reference
You won't memorize every style property up front, but these cover the vast majority of what you'll write day to day:
| Property | Purpose |
|---|---|
backgroundColor | Fill color of a component, e.g. '#ffffff' or 'skyblue' |
padding / paddingTop etc. | Space inside a component's border, between the border and its content |
margin / marginTop etc. | Space outside a component's border, between it and its neighbors |
borderRadius | Rounds the corners of a component |
borderWidth / borderColor | Draws a border around a component |
fontSize | Text size — only valid on <Text> (and its descendants) |
fontWeight | Text boldness, e.g. 'bold' or '600' — only on <Text> |
color | Text color — only valid on <Text>, not on <View> |
color, fontSize, and fontWeight only apply to <Text> components (and text nested inside them). Setting color on a <View> has no effect — a common early mistake.Units: Just Numbers, No px/em/%
On the web, CSS has multiple length units — px, em, rem,
%, vh/vw, and more, each with its own rules. React Native
simplifies this dramatically: for most numeric style values (like padding,
margin, fontSize, width, height), you write a
plain, unitless number, and it is interpreted as a density-independent
pixel — a unit that automatically scales consistently across devices with different
screen densities.
const styles = StyleSheet.create({
box: {
width: 100, // not "100px" — just the number 100
height: 100,
padding: 16,
},
});
Some properties, like width, also accept a percentage string
(e.g. width: '50%'), which is resolved relative to the parent container — but plain
numbers are the default and by far the most common case. Overall, this is simpler than juggling
web CSS's many unit types: in React Native, "a number" almost always means "a scalable pixel,"
full stop.
Property Names Are camelCase, Not kebab-case
One more detail that trips up developers coming from web CSS: because style objects are plain JavaScript objects, their keys follow JavaScript's naming convention — camelCase — not CSS's dash-separated kebab-case.
// React Native (correct) — camelCase, because it's a JS object key
{ backgroundColor: '#ffffff' }
// Web CSS (different world) — kebab-case
/* background-color: #ffffff; */
This isn't a stylistic choice — it's a consequence of what a style object actually is: an
ordinary JavaScript object literal, where background-color would be invalid
syntax (JavaScript would try to read it as subtraction). Once you remember "these are just JS
object keys," the camelCase naming becomes automatic.