React Native – Core Components

June 16, 20263 min readUpdated 8/24/2026

There is no DOM. No <div>, no <span>, no document. React Native gives you a small set of components that map onto real native views, and everything you build is made of them.

The ones you will use every day

View is the container — the <div> of React Native. It lays out its children with flexbox and draws a background, a border and a shadow.

Text displays text, and here is the rule that catches every web developer: text cannot live outside a Text. Putting a bare string in a View is an error, not a shortcut.

Image shows an image. A remote one needs explicit dimensions — there is no layout pass that waits to discover them.

Pressable makes anything tappable. ScrollView scrolls its children. TextInput takes typed input. FlatList renders long lists efficiently. That is very nearly the whole vocabulary; lessons 7, 8 and 9 take the last three in turn.

Nothing inherits

This is the difference that reshapes how you write components.

On the web, a font-size on a wrapper reaches every descendant. In React Native it reaches nothing. A style set on a View does not apply to the Text inside it, and even nested Text only inherits on iOS.

So every piece of text on every screen names its own size, weight and colour. Do that inline and you end up with a hundred slightly different greys. The fix is to stop writing text styles at call sites and define a closed set once:

export function Text({
  variant = 'body',
  tone = 'default',
  center = false,
  style,
  ...rest
}: TextProps) {
  return (
    <RNText
      style={[styles[variant], toneStyles[tone], center && styles.center, style]}
      {...rest}
    />
  );
}

That wrapper is the app's own Text, and every screen imports it instead of React Native's. variant picks a size and weight; tone picks a colour. It is the native equivalent of the utility classes a web app gets from Bootstrap or Tailwind — except here you have to build it, because there is no stylesheet to put them in.

Note the style array. React Native merges them left to right, so the caller's style coming last means a one-off override still wins. That ordering is a convention worth applying to every component you wrap.

Pressable

Older code uses TouchableOpacity, TouchableHighlight and two more. Pressable replaced all of them, and its best feature is that style can be a function:

      style={({ pressed }) => [
        styles.base,
        sizeStyles[size],
        variantStyles[variant],
        fullWidth && styles.fullWidth,
        pressed && !isDisabled && pressedStyles[variant],
        isDisabled && styles.disabled,
        style,
      ]}

The function receives the interaction state and returns styles. That is how a pressed state is expressed without any animation code and without a useState — there is no :active pseudo-class to hook, so the API hands you the state directly.

A false in a style array is ignored, which is what makes condition && style the idiom for conditional styling.

Accessibility is not free

A web <button> announces itself as a button, reports when it is disabled, and is reachable by keyboard. A Pressable is a View that responds to touch and announces nothing. You declare it:

      accessibilityRole="button"
      accessibilityLabel={accessibilityLabel ?? title}
      accessibilityState={{ disabled: isDisabled, selected }}
      hitSlop={8}

accessibilityRole is what makes VoiceOver say "button" instead of reading the label as loose text. accessibilityState is what makes a disabled or selected control announce as such.

hitSlop is a mobile-only concern with no web equivalent: it expands the touch target without changing the layout. Apple asks for 44dp and Android for 48dp, and a small chip is often visually smaller than both. Lesson 20 goes further.

Wrapping, not re-inventing

Most components in a real app are thin wrappers that make one decision consistently:

export function Card({ flush = false, style, ...rest }: CardProps) {
  return <View style={[styles.card, !flush && styles.padded, style]} {...rest} />;
}

Nine lines including its styles, and it means no screen ever writes a card's radius or shadow again. Spreading ...rest keeps every View prop available, so the wrapper constrains nothing.

What has no equivalent

Worth knowing early, so you stop looking. There is no <table>, no <form> element, no <select>, no <input type="radio"> and no <input type="checkbox">. Radios and checkboxes are drawn — a circle with a smaller circle inside — which is exactly why the accessibility props above are not optional. Nothing else tells a screen reader what the shape means.

What is next

Styling and a Design System — how those style objects work, and why a design system stops being optional.