← Back to blog

How to Read React Code as a Designer

React code looks intimidating at first. Here's a practical guide to decoding it using concepts you already know from Figma.

Amarneethi·
How to Read React Code as a Designer

Reasons why it feels alien

When designers see React code for the first time, the instinct is to back away. Angle brackets, curly braces, unfamiliar keywords — it looks like a different language. The good news is that there are fewer patterns to learn than it seems.

Let's break it down.

The Basic Shape of a React Component

Here's the simplest React component you'll encounter:

export default function HelloWorld() {
  return (
    <div className='p-4 text-gray-900'>
      <p>Hello, world</p>
    </div>
  );
}

Reading it top to bottom:

className vs class

If you've ever seen HTML, you might know that class is used to apply styles (colors, fonts, font size, padding, gap, border, corner radius, etc.). In React, it's className instead — a small quirk, but important to know so it doesn't trip you up.

Tailwind Classes Are Figma Properties

When you see className="p-4 text-gray-900 rounded-xl border", you're looking at design decisions written as utility classes:

Tailwind classFigma equivalent
p-4Padding: 16
text-blackText colour: black
rounded-xlCorner radius: 12
borderStroke: 1px

Once you know a handful of these mappings, AI-generated code becomes much more readable. You can scan a className and immediately visualise what the element looks like.

Nesting = Layers

The nesting in JSX (the HTML-like part of React) maps directly to Figma's layer hierarchy:

<div>
  {' '}
  {/* Frame */}
  <div>
    {' '}
    {/*   Frame */}
    <p>Title</p> {/*     Text */}
    <p>Body</p> {/*     Text */}
  </div>
</div>

Each indented level is a child inside a parent. Exactly like nesting frames in Figma.

Curly Braces Mean "JavaScript Here"

Whenever you see { and }, it means "stop treating this as markup/plain text and evaluate it as JavaScript":

<p>Hello, {name}</p>

This renders "Hello, Amarneethi" if name variable is the string "Amarneethi". Think of it like a Figma text layer with a variable bound to it.

What to Do When You Don't Understand Something

Copy the confusing snippet and paste it into Claude or ChatGPT with the prompt: "Explain this React code to me as if I'm a designer who knows Figma but not code."

You'll get a plain-English explanation. Do this enough times, and the patterns start to feel familiar on their own.

DIY Exercise

Info

Copy paste the code snippets below into an AI chat and ask it to explain them. Try to understand the patterns without worrying about the syntax.

1. Component Composition

AI models generate self-contained components. Understanding how smaller pieces (a button, a card, an input) nest inside larger ones (a form, a dashboard, a page) lets you speak the same language as the generated code and request changes precisely — "move the avatar component inside the header" instead of "move that circle thing up."

Example 1 Code

function Avatar({ src, name, size = 'md' }) {
  const sizes = {
    sm: 'w-8 h-8 text-xs',
    md: 'w-12 h-12 text-sm',
    lg: 'w-16 h-16 text-base',
  };
  return (
    <div
      className={`${sizes[size]} rounded-full bg-gradient-to-br from-violet-500 to-fuchsia-500 flex items-center justify-center text-white font-bold shrink-0`}
    >
      {name.charAt(0)}
    </div>
  );
}

function UserCard({ name, role }) {
  return (
    <div className='flex items-center gap-3 p-3 rounded-xl bg-white/60 backdrop-blur border border-gray-200'>
      <Avatar name={name} />
      <div>
        <p className='font-semibold text-gray-900'>{name}</p>
        <p className='text-sm text-gray-500'>{role}</p>
      </div>
    </div>
  );
}
function CompositionExample1() {
  const team = [
    { name: 'Aarav Mehta', role: 'Design Lead' },
    { name: 'Priya Sharma', role: 'Engineer' },
    { name: 'Rohan Kapoor', role: 'PM' },
  ];
  return (
    <div className='space-y-3 p-6 bg-gray-50 rounded-2xl max-w-sm'>
      <h3 className='font-bold text-gray-800 text-lg'>Design Team</h3>
      {team.map((person) => (
        <UserCard key={person.name} name={person.name} role={person.role} />
      ))}
    </div>
  );
}

Output

Design Team

A

Aarav Mehta

Design Lead

P

Priya Sharma

Engineer

R

Rohan Kapoor

PM

Example 2 Code

function NavItem({ icon, label, active = false }) {
  return (
    <button
      className={`flex items-center gap-3 w-full px-4 py-2.5 rounded-lg text-left transition-colors ${
        active
          ? 'bg-indigo-100 text-indigo-700 font-semibold'
          : 'text-gray-600 hover:bg-gray-100'
      }`}
    >
      <span className='text-lg'>{icon}</span>
      <span className='text-sm'>{label}</span>
    </button>
  );
}

function CompositionExample2() {
  return (
    <nav className='w-56 p-4 bg-white rounded-2xl border border-gray-200 space-y-1'>
      <p className='text-xs font-bold text-gray-400 uppercase tracking-wider px-4'>
        Menu
      </p>
      <NavItem icon={<Gauge size='12' />} label='Dashboard' active />
      <NavItem icon={<ChartNoAxesCombined size='12' />} label='Analytics' />
      <NavItem icon={<User2 size='12' />} label='Profile' />
      <NavItem icon={<Settings size='12' />} label='Settings' />
    </nav>
  );
}

Output

Example 3 Code

function Badge({ label, color = 'blue' }) {
  const colors = {
    blue: 'bg-blue-100 text-blue-700',
    green: 'bg-emerald-100 text-emerald-700',
    orange: 'bg-orange-100 text-orange-700',
  };
  return (
    <span
      className={`text-xs font-semibold px-2.5 py-1 rounded-full ${colors[color]}`}
    >
      {label}
    </span>
  );
}

function ProjectCard({ title, status, color }) {
  return (
    <div className='p-4 rounded-xl bg-white border border-gray-200 space-y-2'>
      <Badge label={status} color={color} />
      <h4 className='font-semibold text-gray-900'>{title}</h4>
      <div className='w-full h-1.5 bg-gray-100 rounded-full overflow-hidden'>
        <div
          className='h-full bg-indigo-500 rounded-full'
          style={{ width: '65%' }}
        />
      </div>
    </div>
  );
}

function CompositionExample3() {
  return (
    <div className='grid grid-cols-1 sm:grid-cols-3 gap-4 max-w-2xl'>
      <ProjectCard title='Brand Refresh' status='In Progress' color='blue' />
      <ProjectCard title='Mobile App' status='Review' color='orange' />
      <ProjectCard title='Design System' status='Done' color='green' />
    </div>
  );
}

Output

In Progress

Brand Refresh

Review

Mobile App

Done

Design System

2. Props as Design Tokens

Props are how React components accept variation — think of them as the knobs on a design system component. When AI generates <Button variant="primary" size="lg">, those props map directly to your design tokens. Learning this pattern means you can request exactly the variants you need and audit whether the output matches your design system.

Example 1 Code

function PropsExample1() {
  const base =
    'inline-flex items-center justify-center font-semibold rounded-xl transition-all active:scale-95';
  const variants = {
    primary: 'bg-gray-900 text-white hover:bg-gray-700',
    secondary:
      'bg-gray-100 text-gray-800 hover:bg-gray-200 border border-gray-200',
    danger: 'bg-red-500 text-white hover:bg-red-600',
  };
  const sizes = {
    sm: 'text-sm px-3.5 py-1.5',
    md: 'text-sm px-5 py-2.5',
    lg: 'text-base px-7 py-3',
  };
  return (
    <div className='flex flex-wrap gap-3 items-center'>
      {['primary', 'secondary', 'danger'].map((v) =>
        ['sm', 'md', 'lg'].map((s) => (
          <button key={v + s} className={`${base} ${variants[v]} ${sizes[s]}`}>
            {v} / {s}
          </button>
        )),
      )}
    </div>
  );
}

Output

Example 2 Code

function Alert({ intent = 'info', children }) {
  const styles = {
    info: {
      bg: 'bg-sky-50 border-sky-200',
      icon: <Info size={18} />,
      text: 'text-sky-800',
    },
    success: {
      bg: 'bg-emerald-50 border-emerald-200',
      icon: <CheckCircle size={18} />,
      text: 'text-emerald-800',
    },
    warning: {
      bg: 'bg-amber-50 border-amber-200',
      icon: <AlertCircle size={18} />,
      text: 'text-amber-800',
    },
    error: {
      bg: 'bg-red-50 border-red-200',
      icon: <OctagonAlert size={18} />,
      text: 'text-red-800',
    },
  };
  const s = styles[intent];
  return (
    <div className={`flex items-center gap-3 p-4 rounded-xl border ${s.bg}`}>
      <span className={`text-lg ${s.text}`}>{s.icon}</span>
      <p className={`text-sm ${s.text}`}>{children}</p>
    </div>
  );
}

function PropsExample2() {
  return (
    <div className='space-y-3 max-w-md'>
      <Alert intent='info'>Your trial expires in 3 days.</Alert>
      <Alert intent='success'>Payment received successfully!</Alert>
      <Alert intent='warning'>Storage is almost full.</Alert>
      <Alert intent='error'>Failed to save changes.</Alert>
    </div>
  );
}

Output

Your trial expires in 3 days.

Payment received successfully!

Storage is almost full.

Failed to save changes.

Example 3 Code

function Tag({ label, color = 'gray', rounded = false }) {
  const colors = {
    gray: 'bg-gray-100 text-gray-700',
    purple: 'bg-purple-100 text-purple-700',
    teal: 'bg-teal-100 text-teal-700',
    pink: 'bg-pink-100 text-pink-700',
  };
  return (
    <span
      className={`inline-block text-xs font-medium px-3 py-1 ${rounded ? 'rounded-full' : 'rounded-md'} ${colors[color]}`}
    >
      {label}
    </span>
  );
}

function PropsExample3() {
  return (
    <div className='space-y-4'>
      <div className='flex gap-2'>
        <Tag label='Default' />
        <Tag label='Purple' color='purple' />
        <Tag label='Teal' color='teal' />
        <Tag label='Pink' color='pink' />
      </div>
      <div className='flex gap-2'>
        <Tag label='Rounded' rounded />
        <Tag label='Purple Pill' color='purple' rounded />
        <Tag label='Teal Pill' color='teal' rounded />
        <Tag label='Pink Pill' color='pink' rounded />
      </div>
    </div>
  );
}

Output

DefaultPurpleTealPink
RoundedPurple PillTeal PillPink Pill

3. Event-Driven UI

Everything interactive in React starts with an event — a click, a keystroke, a form submission, a scroll, a hover. AI-generated code wires these up with handlers like onClick, onChange, and onSubmit. As a designer, thinking in events rather than static screens is the fundamental shift: every interaction you design is really an event that triggers a response.

State is (must be) the result of events. When a user clicks a "like" button (event), the heart fills in because the state changed from false to true. When someone types in a search field (onChange event), the filtered list updates because the state now holds their query. Learning to trace this chain — event happens → state updates → UI re-renders — gives you a complete mental model of how AI-generated interfaces actually work. It also means you can prompt more precisely: "on click, toggle the isExpanded state and show the detail panel" instead of vaguely asking for "an expandable card."

Example 1 Code

function EventExample1() {
  const [liked, setLiked] = useState(false);
  const [count, setCount] = useState(42);

  function handleLike() {
    setLiked(!liked);
    setCount((c) => (liked ? c - 1 : c + 1));
  }

  return (
    <div className='flex items-center gap-6 p-6 bg-white rounded-2xl border border-gray-200 max-w-xs'>
      <img
        className='w-20 h-20 rounded-xl object-cover bg-gray-100'
        src='https://picsum.photos/seed/design/200'
        alt=''
      />
      <div className='space-y-2'>
        <p className='font-semibold text-gray-900'>Sunset Photo</p>
        <button
          onClick={handleLike}
          className='flex items-center gap-1.5 text-sm transition-transform active:scale-90'
        >
          <span
            className={`text-xl transition-colors ${liked ? 'text-red-500' : 'text-gray-300'}`}
          >
            {liked ? '♥' : '♡'}
          </span>
          <span className='text-gray-600'>{count}</span>
        </button>
      </div>
    </div>
  );
}

Output

Sunset Photo

Example 2 Code

function EventExample2() {
  const [query, setQuery] = useState("");
  const fruits = ["Apple", "Banana", "Cherry", "Dragonfruit", "Elderberry", "Fig", "Guava", "Honeydew"];
  const filtered = fruits.filter((f) => f.toLowerCase().includes(query.toLowerCase()));

return (
<div className="max-w-xs space-y-3">
<input
type="text"
placeholder="Search fruits…"
value={query}
onChange={(e) => setQuery(e.target.value)}
className="w-full px-4 py-2.5 rounded-xl border border-gray-200 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500/30 focus:border-indigo-400"
/>
<ul className="space-y-1">
{filtered.map((f) => (
<li key={f} className="px-4 py-2 rounded-lg bg-gray-50 text-sm text-gray-700">{f}</li>
))}
{filtered.length === 0 && (
<li className="px-4 py-2 text-sm text-gray-400 italic">No results</li>
)}
</ul>
</div>
);
}

Output

  • Apple
  • Banana
  • Cherry
  • Dragonfruit
  • Elderberry
  • Fig
  • Guava
  • Honeydew

Example 3 Code

function EventExample3() {
  const [items, setItems] = useState(["Learn React", "Ship v1"]);
  const [value, setValue] = useState("");

  function handleSubmit(e) {
    e.preventDefault();
    if (!value.trim()) return;
    setItems([...items, value.trim()]);
    setValue("");
  }

  return (
    <div className="max-w-xs space-y-3">
      <form onSubmit={handleSubmit} className="flex gap-2">
        <input
          value={value}
          onChange={(e) => setValue(e.target.value)}
          placeholder="Add a task…"
          className="flex-1 px-4 py-2.5 rounded-xl border border-gray-200 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500/30 focus:border-indigo-400"
        />
        <button type="submit" className="px-4 py-2.5 bg-gray-900 text-white text-sm font-semibold rounded-xl hover:bg-gray-700 active:scale-95 transition-all">
          Add
        </button>
      </form>
      <ul className="space-y-1">
        {items.map((item, i) => (
          <li key={i} className="px-4 py-2.5 rounded-lg bg-gray-50 text-sm text-gray-700 flex items-center gap-2">
            <span className="w-5 h-5 rounded-md border-2 border-gray-300 shrink-0" />
            {item}
          </li>
        ))}
      </ul>
    </div>
  );
}

Output

  • Learn React
  • Ship v1

4. Conditional Rendering

This is the code equivalent of "show this only when…" — a banner that appears on first visit, an error message on failed validation, a skeleton screen while data loads. AI code handles this with ternaries and logical operators. Knowing this pattern lets you spec interactions without ambiguity: "render the empty state when items.length === 0."

Example 1 Code

function ConditionalExample1() {
  const [loggedIn, setLoggedIn] = useState(false);
  return (
    <div className='p-6 rounded-2xl bg-white border border-gray-200 max-w-xs space-y-4'>
      {loggedIn ? (
        <div className='space-y-3'>
          <div className='flex items-center gap-3'>
            <div className='w-10 h-10 rounded-full bg-gradient-to-br from-emerald-400 to-teal-500 flex items-center justify-center text-white font-bold'>
              A
            </div>
            <div>
              <p className='font-semibold text-gray-900 text-sm'>Aarav Mehta</p>
              <p className='text-xs text-gray-500'>aarav@example.com</p>
            </div>
          </div>
          <button
            onClick={() => setLoggedIn(false)}
            className='w-full py-2 text-sm text-red-600 bg-red-50 rounded-xl hover:bg-red-100 transition-colors'
          >
            Log Out
          </button>
        </div>
      ) : (
        <div className='space-y-3 text-center'>
          <p className='text-gray-500 text-sm'>You are not signed in.</p>
          <button
            onClick={() => setLoggedIn(true)}
            className='w-full py-2.5 text-sm font-semibold text-white bg-gray-900 rounded-xl hover:bg-gray-700 active:scale-95 transition-all'
          >
            Sign In
          </button>
        </div>
      )}
    </div>
  );
}

Output

You are not signed in.

Example 2 Code

function ConditionalExample2() {
  const [email, setEmail] = useState('');
  const [touched, setTouched] = useState(false);
  const isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
  const showError = touched && !isValid;

  return (
    <div className='max-w-xs space-y-2'>
      <label className='text-sm font-medium text-gray-700'>Email address</label>
      <input
        type='email'
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        onBlur={() => setTouched(true)}
        className={`w-full px-4 py-2.5 rounded-xl border text-sm focus:outline-none transition-colors ${
          showError
            ? 'border-red-400 focus:ring-2 focus:ring-red-200'
            : 'border-gray-200 focus:ring-2 focus:ring-indigo-500/30 focus:border-indigo-400'
        }`}
        placeholder='you@example.com'
      />
      {showError && (
        <p className='text-xs text-red-500 flex items-center gap-1'>
          <span>⚠</span> Please enter a valid email address.
        </p>
      )}
      {touched && isValid && (
        <p className='text-xs text-emerald-600 flex items-center gap-1'>
          <span>✓</span> Looks good!
        </p>
      )}
    </div>
  );
}

Output

Example 3 Code

function ConditionalExample3() {
  const [notifications, setNotifications] = useState([]);

function addRandom() {
const msgs = ["New comment on your post", "You were mentioned in #design", "Build succeeded", "Priya invited you"];
setNotifications((prev) => [...prev, msgs[prev.length % msgs.length]]);
}

return (
<div className="max-w-xs space-y-3">
<div className="flex items-center justify-between">
<h3 className="font-bold text-gray-800">Notifications</h3>
<button onClick={addRandom} className="text-xs text-indigo-600 font-semibold hover:underline"> + Simulate
</button>
</div>

      {notifications.length === 0 ? (
        <div className="py-10 text-center">
          <p className="text-3xl mb-2">🔔</p>
          <p className="text-sm text-gray-400">All caught up — nothing here!</p>
        </div>
      ) : (
        <ul className="space-y-2">
          {notifications.map((msg, i) => (
            <li key={i} className="flex items-start gap-3 p-3 rounded-xl bg-indigo-50 text-sm text-gray-700">
              <span className="w-2 h-2 mt-1.5 rounded-full bg-indigo-500 shrink-0" />
              {msg}
            </li>
          ))}
        </ul>
      )}
    </div>

);
}

Output

Notifications

🔔

All caught up — nothing here!

5. The map() List Pattern

Anytime you design a repeating element — a card grid, a table row, a notification list — the AI will use .map() to loop over data and render each item. Understanding this pattern helps you think in terms of a single template item plus variable data, which is exactly how you should hand off list-based designs.

Example 1 Code

function MapExample1() {
  const users = [
    { id: 1, name: "Aarav Mehta", email: "aarav@example.com" },
    { id: 2, name: "Priya Sharma", email: "priya@example.com" },
    { id: 3, name: "Rohan Kapoor", email: "rohan@example.com" },
    { id: 4, name: "Diya Nair", email: "diya@example.com" },
  ];
  return (
    <div className="divide-y divide-gray-100 rounded-2xl border border-gray-200 overflow-hidden max-w-sm">
      {users.map((user) => (
        <div key={user.id} className="flex items-center gap-3 px-4 py-3 bg-white hover:bg-gray-50 transition-colors">
          <div className="w-9 h-9 rounded-full bg-gradient-to-br from-violet-400 to-fuchsia-400 flex items-center justify-center text-white text-sm font-bold">
            {user.name.charAt(0)}
          </div>
          <div>
            <p className="text-sm font-medium text-gray-900">{user.name}</p>
            <p className="text-xs text-gray-400">{user.email}</p>
          </div>
        </div>
      ))}
    </div>
  );
}

Output

A

Aarav Mehta

aarav@example.com

P

Priya Sharma

priya@example.com

R

Rohan Kapoor

rohan@example.com

D

Diya Nair

diya@example.com

Example 2 Code

function MapExample2() {
  const plans = [
    { name: "Starter", price: 0, features: ["1 project", "Basic analytics", "Community support"] },
    { name: "Pro", price: 29, features: ["Unlimited projects", "Advanced analytics", "Priority support", "Custom domain"] },
    { name: "Enterprise", price: 99, features: ["Everything in Pro", "SSO & SAML", "Dedicated CSM", "SLA guarantee", "Audit logs"] },
  ];
  return (
    <div className="grid grid-cols-1 sm:grid-cols-3 gap-4 max-w-3xl">
      {plans.map((plan) => (
        <div key={plan.name} className="p-5 bg-white rounded-2xl border border-gray-200 flex flex-col">
          <p className="text-sm font-bold text-gray-400 uppercase tracking-wide">{plan.name}</p>
          <p className="mt-2 text-3xl font-extrabold text-gray-900">
            ${plan.price}<span className="text-base font-normal text-gray-400">/mo</span>
          </p>
          <ul className="mt-4 space-y-2 flex-1">
            {plan.features.map((f) => (
              <li key={f} className="flex items-center gap-2 text-sm text-gray-600">
                <span className="text-emerald-500">✓</span> {f}
              </li>
            ))}
          </ul>
          <button className="mt-5 w-full py-2.5 rounded-xl text-sm font-semibold bg-gray-900 text-white hover:bg-gray-700 active:scale-95 transition-all">
            Choose {plan.name}
          </button>
        </div>
      ))}
    </div>
  );
}

Output

Starter

$0/mo

  • 1 project
  • Basic analytics
  • Community support

Pro

$29/mo

  • Unlimited projects
  • Advanced analytics
  • Priority support
  • Custom domain

Enterprise

$99/mo

  • Everything in Pro
  • SSO & SAML
  • Dedicated CSM
  • SLA guarantee
  • Audit logs

Example 3 Code

function MapExample3() {
  const stats = [
    { label: "Revenue", value: "₹12.4L", change: "+12%", up: true },
    { label: "Users", value: "8,842", change: "+4.3%", up: true },
    { label: "Bounce Rate", value: "32%", change: "-2.1%", up: false },
    { label: "Avg. Session", value: "4m 12s", change: "+8%", up: true },
  ];
  return (
    <div className="grid grid-cols-2 sm:grid-cols-4 gap-4 max-w-2xl">
      {stats.map((s) => (
        <div key={s.label} className="p-4 bg-white rounded-2xl border border-gray-200">
          <p className="text-xs text-gray-400 font-medium">{s.label}</p>
          <p className="text-2xl font-bold text-gray-900 mt-1">{s.value}</p>
          <p className={`text-xs font-semibold mt-1 ${s.up ? "text-emerald-600" : "text-red-500"}`}>
            {s.change}
          </p>
        </div>
      ))}
    </div>
  );
}

Output

Revenue

₹12.4L

+12%

Users

8,842

+4.3%

Bounce Rate

32%

-2.1%

Avg. Session

4m 12s

+8%

These 5 patterns cover roughly 80% of what you'll encounter in AI-generated React. Mastering them turns you from someone who simply shoots in the dark into someone who can read, direct, and refine with AI.

The Payoff

The moment you can read a React component and roughly understand its structure, you become a much more effective collaborator with AI. You can verify that what it generated matches your intent. You can ask for specific changes. You can spot when it's gone off-track.

You don't need to write React from scratch to benefit from understanding it. You just need to read it well enough to direct AI.