Setup & first component.
Three commands to running React.
Vite made React setup trivial. Three commands, sixty seconds, and you have a working React app. This lesson walks through the setup, explains JSX (the syntax that makes React readable), writes your first component, and shows you exactly how React takes that component and turns it into DOM. No webpack configuration. No create-react-app. Just the modern, simple way.
Install React with Vite: npm create vite@latest my-app -- --template react, then cd my-app, then npm install, then npm run dev. That's it. Vite handles JSX compilation, hot reload, and bundling. Your first component is a JavaScript function that returns JSX — HTML-like syntax compiled to React.createElement calls. Modern React is 90% JavaScript, 10% JSX syntax.
Before this lesson: you must know JavaScript (functions, arrays, objects, arrow functions, destructuring). If not, complete the JavaScript track first.
⚙️ Setup — three commands
Vite is the modern standard. Faster than create-react-app, simpler than webpack.
Before you start, make sure Node.js is installed. Open a terminal and run node --version. If you see a version number (18+), you're set. If not, install Node from nodejs.org — the LTS version is fine.
# 1. Create a new React project npm create vite@latest my-app -- --template react # 2. Enter the project folder cd my-app # 3. Install dependencies npm install # 4. Start the dev server npm run dev VITE v5.4.0 ready in 412 ms ➜ Local: http://localhost:5173/ ➜ Network: use --host to expose
Open http://localhost:5173 in your browser. You should see the default Vite + React starter page. Change any file in src/ and the browser updates instantly — that's hot module replacement, and it's the reason Vite became the standard.
Why Vite?
create-react-app is deprecated and slow. Webpack requires 200 lines of config. Vite is fast (native ES modules in dev), zero-config, and the official recommendation from the React team.
What you get
A dev server with hot reload, JSX compilation, ES module support, and a build command. All the tooling you need for a real project, configured out of the box.
The file structure
src/ holds your components. index.html is the entry (with <div id="root"></div>). src/main.jsx is the JS entry. package.json has scripts: dev, build, preview.
Node.js version
Vite 5+ requires Node 18 or higher. Check with node --version. If you're on an older version, install the LTS from nodejs.org. Older Node versions cause cryptic errors.
Don't use create-react-app. It was the standard for years but is now officially deprecated by the React team. It's slow, uses an outdated webpack config, and hasn't been updated meaningfully. Vite is the modern answer — it's what React's own documentation now recommends. If you see a tutorial using create-react-app, it's a few years out of date.
📝 JSX — the syntax that makes React readable
HTML-like code inside JavaScript. Compiled at build time. Not magic.
JSX looks like HTML but is JavaScript. When you write <div>Hello</div>, the compiler turns it into React.createElement('div', null, 'Hello'). The JSX syntax is just a convenience — nothing more. Every JSX expression compiles to a plain JavaScript function call.
// What you write <div className="card"> <h2>{title}</h2> <p>{description}</p> </div> // What it compiles to (approximately) React.createElement( 'div', { className: 'card' }, React.createElement('h2', null, title), React.createElement('p', null, description) ) // The JSX version is obviously more readable. // The JavaScript version is what React actually uses. // Same result — JSX is just the input syntax. // ───────────────────────────────────────── // JSX rules that differ from HTML: // 1. className, not class <div className="button"> // 2. Self-closing tags required <img src="photo.jpg" /> // not <img src="photo.jpg"> <br /> <input /> // 3. JavaScript expressions in {} <p>{2 + 2}</p> // renders "4" <p>{user.name}</p> // renders the name <p>{isActive ? 'On' : 'Off'}</p> // 4. camelCase attributes <div onClick={handleClick}> <input onChange={handleChange} /> <label htmlFor="email"> // 5. Inline styles as objects <div style={{ color: 'red', fontSize: '16px' }}> // Note the double curly braces: outer = expression, inner = object // 6. Comments use {/* */} {/* this is a comment in JSX */}
className vs class
class is reserved in JavaScript (used for classes). JSX uses className. Same for htmlFor instead of for. These are the two most common JSX differences.
{ } — the JavaScript escape
Curly braces let you embed JavaScript in JSX. Numbers, strings, variables, function calls, ternaries — anything that evaluates to a value. {2 + 2} renders "4".
Self-closing tags
Every tag must be closed. <div> is invalid — it must be <div></div> or <div />. This is the #1 syntax error for HTML developers.
Inline styles
style={{{{ color: 'red' }}}} — note the double braces. The outer is the JSX expression, the inner is a JavaScript object. CSS property names are camelCase.
JSX is not HTML. It looks like it, but the rules are different. The most common errors: forgetting to close a tag (<div> without </div>), using class instead of className, using for instead of htmlFor, and forgetting that inline styles are objects. Each of these fails at compile time with a specific error message — read the message, it tells you exactly what's wrong.
🧩 Your first component
A function that returns JSX. That's the entire definition.
Open src/App.jsx in your editor. Replace everything in it with this:
function App() { const name = 'Alice'; const age = 28; return ( <div style={{ padding: '2rem', fontFamily: 'system-ui' }}> <h1>Hello, {name}!</h1> <p>You are {age} years old.</p> <p>In 10 years you'll be {age + 10}.</p> </div> ); } export default App;
Save the file. The browser updates automatically. You should see:
Hello, Alice! You are 28 years old. In 10 years you'll be 38.
Now try adding a clickable button. This is where React's event handling starts to make sense:
function App() { function handleClick() { alert('Button clicked!'); } return ( <div style={{ padding: '2rem' }}> <h1>Click the button below</h1> <button onClick={handleClick}> Click me </button> </div> ); } export default App;
Component = function
A React component is a JavaScript function that returns JSX. That's it. No class, no inheritance, no decorators. Just a function.
Capital letter
Component names start with a capital letter. App, not app. React uses the case to distinguish components from HTML tags: <div> is HTML, <App /> is a component.
Return JSX
The function's return value is JSX. If you return multiple elements, wrap them in a single parent or a Fragment (<>...</>). React requires one root element per return.
Export default
Each component file exports the component so it can be imported elsewhere. export default App at the bottom. The name matters — you import it by that name.
Components are just functions. If you've written JavaScript, you already know how to write React components. The only new syntax is JSX, and that's a small addition. Everything else — variables, functions, conditionals, arrays — works exactly like JavaScript. That's why the JavaScript foundation matters so much: once you have it, React becomes a small addition, not a new language.
🎬 How React renders to the DOM
The connection between your component function and the pixels on screen.
Open src/main.jsx. This is the entry point — the file that tells React what to render and where:
import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import App from './App.jsx'; import './index.css'; const root = createRoot(document.getElementById('root')); root.render( <StrictMode> <App /> </StrictMode> );
And index.html has the root div that React targets:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>My React App</title>
</head>
<body>
<div id="root"></div> <!-- React renders here -->
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
createRoot
Finds the #root div in the HTML and tells React "this is where you mount the app." React takes over that element and controls everything inside it.
render(<App />)
Calls the App component, gets back a JSX tree, and renders it into the root div. From this point on, React owns the DOM inside #root.
StrictMode
A development-only wrapper that double-invokes components to catch bugs. Doesn't affect production. Leave it on — it's a useful safety net.
One render call
You only call root.render() once. React manages all future updates through state. This is the declarative model — you don't tell React what changed, you change state and React handles it.
The mental model that makes React click. You don't write "add this element to the DOM." You write "here's what the UI should look like given this state." When state changes, React re-runs your component function, compares the new JSX tree to the old one, and patches only the differences. That's it. That's the entire model. Once you internalize "UI = function of state," React becomes simple — and this simple model is what makes large apps manageable.
🏆 Challenge
Three tasks. Each exercises a different React concept.
Task 1 — Extend the component
Take the App component from this lesson. Add:
1. A paragraph showing your favorite language (e.g., "My favorite language is React")
2. A conditional: if the language is React, show "Great choice!" in green; otherwise show "Consider React" in gray
3. A list of three favorite technologies using .map() to render them as <li> elements
4. A button that changes the language when clicked (hint: you'll need useState — check the next lesson if you want a head start)
This gets you from "renders JSX" to "renders conditional, dynamic content" — the foundation of every React app.
Task 2 — Create a second component
Create a new file src/Welcome.jsx:
1. Define a function component called Welcome
2. It returns a simple card: a div with a heading and a paragraph
3. Export it with export default Welcome
4. Import it in App.jsx and render it below the existing content
The point: understand how components compose. App renders Welcome, which renders its own JSX. This is how all React apps are built — small components nested inside larger ones.
Task 3 — Break it intentionally
Try these broken pieces of code one at a time. Each fails for a different reason — read the error messages:
1. Use class="card" instead of className="card"
2. Write <div> without a closing </div>
3. Return two sibling <div> elements without a wrapper
4. Name the component app (lowercase) and use <app />
5. Forget to export default App
For each, note the specific error message. Once you've seen the errors once, you'll recognize them forever. Every React developer has hit every one of these.
⚠️ Common mistakes
The setup and JSX bugs that catch every beginner.
It's deprecated and slow. Fix: use Vite. npm create vite@latest my-app -- --template react. This is now the official recommendation.
<div class="card"> produces a warning. Fix: <div className="card">. Same for for → htmlFor.
<img src="..."> works in HTML but fails in JSX. Fix: <img src="..." />. Same for <br />, <input />, and every other self-closing tag.
function app() { ... } and <app /> — React treats <app> as an HTML tag, doesn't find it, and renders nothing. Fix: always capitalize component names.
return (<h1>Hi</h1> <p>There</p>) is a syntax error. Fix: wrap in a single parent (<div>) or a Fragment (<><h1 /><p /></>).
In React 17+, you don't need to import React for JSX. In older versions you did. If you see a React tutorial with import React from 'react' at the top of every file, it's for an older version. React 19 doesn't require it.
<!-- comment --> is an HTML comment and fails inside JSX. Fix: {/* comment */}. The curly braces make it a JavaScript expression, and the comment inside is ignored.
Vite 5+ requires Node 18+. If npm run dev fails with a cryptic error, check node --version. Fix: install LTS Node from nodejs.org. This is the single most common "Vite doesn't work" cause.
❓ Frequently asked questions
How do I install React?
The modern way is Vite. Run three commands: npm create vite@latest my-app -- --template react, then cd my-app, then npm install. After that, npm run dev starts a dev server at localhost:5173. That's the entire setup.
What is JSX and why does React use it?
JSX is a syntax extension that lets you write HTML-like code inside JavaScript. It's not valid JavaScript — it's compiled by Vite into React.createElement calls at build time. React uses it because it's more readable than raw function calls.
What is the difference between className and class in React?
In HTML you write class='button'. In JSX you write className='button'. This is because class is a reserved keyword in JavaScript. Same for htmlFor instead of for on labels.
How does a React component render to the DOM?
In main.jsx, you call createRoot(document.getElementById('root')).render(<App />). React takes the App component, calls its function, gets back a tree of React elements, and efficiently updates the DOM inside the root element.
What is the difference between a component and a regular function?
A React component is a function that returns JSX. It starts with a capital letter. It can accept props. It can use hooks. A regular function can do none of those things.
Do I need to know JSX before React?
No — you learn JSX as part of React. JSX is small. What you DO need to know before React is JavaScript itself — functions, arrays, objects, arrow functions, and destructuring.
Why do components start with a capital letter?
React uses the case to distinguish components from HTML elements. <div> is an HTML element. <MyComponent> is a React component. Lowercase components silently fail to render.
What is a self-closing tag in JSX?
In JSX, ALL tags must be closed — either with an explicit closing tag or as self-closing. Writing <div> without a closing tag is a syntax error. This is the #1 difference from HTML.