π§© What is JSX (JavaScript XML)?
JSX is a syntax extension for JavaScript used with React.
It allows you to write HTML-like code inside JavaScript.
β Why JSX?
Makes code more readable and expressive
Allows UI structure to be written in a familiar HTML style
Helps in visualizing component structure directly inside JavaScript
π Example:
const element = <h1>Hello, React!</h1>;This looks like HTML, but itβs not β itβs JSX!
Behind the scenes, it gets compiled into:
const element = React.createElement("h1", null, "Hello, React!");β Features of JSX:
Can embed JavaScript expressions using
{}const name = "xyz"; const greeting = <h1>Hello, {name}!</h1>;Must return a single root element
Uses camelCase for attributes (
classNameinstead ofclass,htmlForinstead offor)
π§ What is Babel?
Babel is a JavaScript compiler and transpiler.
β What it does:
Converts modern JavaScript (ES6+) and JSX into backward-compatible JavaScript that browsers can understand.
Helps in supporting older browsers by transpiling features they donβt support.
π‘ Without Babel, JSX and ES6+ code wouldnβt work directly in browsers.
π How JSX + Babel work together:
You write JSX in your React component.
Babel converts JSX into regular JavaScript using
React.createElement().The browser runs the converted code.
π Example: How Babel transforms JSX
Input (JSX):
const greeting = <h1>Hello, World!</h1>;const greeting = React.createElement("h1", null, "Hello, World!");<div class="infographic-jsxbabel" id="jb">
<style>
.infographic-jsxbabel {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-deep: #1942a8;
--accent-soft: #e3ebfd;
--line: #ddd6c9;
--radius: 8px;
--display-font: 'Fraunces', Georgia, serif;
--body-font: 'Inter', system-ui, sans-serif;
--mono-font: 'IBM Plex Mono', monospace;
max-width: 880px;
padding: 2rem;
margin: 0 auto;
box-sizing: border-box;
background: transparent;
color: var(--ink);
font-family: var(--body-font);
}
.infographic-jsxbabel[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #13171f;
--paper-alt: #1c212b;
--accent: #5b8def;
--accent-deep: #8fb4ff;
--accent-soft: #20293f;
--line: #2c313d;
}
.infographic-jsxbabel * { box-sizing: border-box; }
.jb-eyebrow {
font-family: var(--mono-font); font-size: 0.72rem; letter-spacing: 0.1em;
text-transform: uppercase; color: var(--accent); margin: 0 0 0.45rem;
display: flex; align-items: center; justify-content: center; gap: 0.4rem;
}
.jb-eyebrow::before { content: ""; width: 14px; height: 2px; background: var(--accent); display: inline-block; }
.jb-title {
font-family: var(--display-font); font-size: clamp(1.5rem, 4vw, 2.3rem); text-align: center;
margin: 0 0 0.55rem; line-height: 1.12; letter-spacing: -0.01em;
}
.jb-sub {
color: var(--ink-soft); font-size: 0.95rem; max-width: 520px; line-height: 1.55; margin: 0 auto 1.6rem;
text-align: center;
}
/* ===== mini pipeline ===== */
.jb-pipeline { display: flex; align-items: center; justify-content: center; gap: 0.5rem; margin-bottom: 1.9rem; flex-wrap: wrap; }
.jb-pipe-node {
display: flex; align-items: center; gap: 0.4rem; font-family: var(--mono-font); font-size: 0.72rem;
font-weight: 600; color: var(--ink); background: var(--paper-alt); border: 1px solid var(--line);
border-radius: 100px; padding: 0.4rem 0.85rem;
}
.jb-pipe-node svg { width: 15px; height: 15px; flex-shrink: 0; }
.jb-pipe-node.jb-pipe-accent { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-deep); }
.jb-pipe-arrow { color: var(--ink-soft); font-size: 0.85rem; }
/* ===== tabs ===== */
.jb-tabs { display: flex; justify-content: center; gap: 0.4rem; margin-bottom: 1.1rem; flex-wrap: wrap; }
.jb-tab {
font: inherit; font-size: 0.78rem; font-weight: 600; font-family: var(--mono-font);
background: var(--paper-alt); border: 1.5px solid var(--line); border-radius: 100px;
padding: 0.45rem 1rem; cursor: pointer; color: var(--ink-soft); transition: all 0.2s;
display: flex; align-items: center; gap: 0.4rem;
}
.jb-tab .jb-tab-num {
width: 16px; height: 16px; border-radius: 50%; background: var(--line); color: #fff;
font-size: 0.65rem; display: flex; align-items: center; justify-content: center; transition: background 0.2s;
}
.jb-tab:hover { border-color: var(--accent); color: var(--ink); }
.jb-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.jb-tab.is-active { background: var(--accent); border-color: var(--accent); color: #fff; }
.jb-tab.is-active .jb-tab-num { background: rgba(255,255,255,0.3); }
/* ===== code panels ===== */
.jb-panel { display: none; }
.jb-panel.is-visible { display: block; }
.jb-code-compare { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem; margin-bottom: 1.1rem; }
.jb-code-block { display: flex; flex-direction: column; }
.jb-code-head { display: flex; align-items: center; justify-content: center; gap: 0.4rem; margin-bottom: 0.5rem; }
.jb-code-head svg { width: 15px; height: 15px; flex-shrink: 0; }
.jb-code-name { font-size: 0.78rem; font-weight: 600; color: var(--ink); }
.jb-code-block pre {
margin: 0; background: #0d0d10; border: 1px solid #24252d; border-radius: var(--radius);
padding: 0.9rem 1rem; overflow: auto; flex: 1;
}
.jb-code-block code { font-family: var(--mono-font); font-size: 0.74rem; line-height: 1.75; color: #d4d4d8; white-space: pre; }
.tok-kw { color: #c678dd; }
.tok-tag { color: #e06c75; }
.tok-attr { color: #d19a66; }
.tok-str { color: #98c379; }
.tok-expr { color: #56b6c2; }
.tok-punc { color: #6b7280; }
.hb-tok { cursor: pointer; border-radius: 4px; padding: 0.05rem 0.15rem; margin: -0.05rem -0.15rem; transition: background 0.15s, opacity 0.15s; }
.hb-tok:hover { background: rgba(255,255,255,0.09); }
.hb-tok:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.hb-tok.is-dim { opacity: 0.3; }
.hb-tok.is-active { background: var(--accent); }
.hb-tok.is-active, .hb-tok.is-active span { color: #fff; }
.jb-caption {
text-align: center; font-size: 0.88rem; color: var(--ink-soft); min-height: 1.4em;
max-width: 520px; margin: 0 auto 1.6rem; line-height: 1.5;
}
@media (max-width: 640px) {
.jb-code-compare { grid-template-columns: 1fr; }
}
.jb-takeaway {
margin-top: 0.3rem; padding: 0.95rem 1.2rem; background: var(--accent-soft);
border-left: 3px solid var(--accent); border-radius: 4px; font-size: 0.9rem; color: var(--ink); line-height: 1.5;
}
.jb-takeaway b { color: var(--accent-deep); }
@media (prefers-reduced-motion: reduce) {
.infographic-jsxbabel *, .infographic-jsxbabel *::before, .infographic-jsxbabel *::after {
transition-duration: 0.001ms !important; animation-duration: 0.001ms !important;
}
}
</style>
<div class="jb-eyebrow">Behind the Scenes</div>
<h1 class="jb-title">JSX & Babel</h1>
<p class="jb-sub">JSX isn't real JavaScript β Babel compiles it into calls the browser can actually run.</p>
<div class="jb-pipeline">
<span class="jb-pipe-node">
<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M6 3 L2 8 L6 13" fill="none" stroke="var(--ink-soft)" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/><path d="M10 3 L14 8 L10 13" fill="none" stroke="var(--ink-soft)" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>
JSX
</span>
<span class="jb-pipe-arrow">β</span>
<span class="jb-pipe-node jb-pipe-accent">
<svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="3.2" fill="none" stroke="var(--accent-deep)" stroke-width="1.4"/><path d="M8 3.2v1.6M8 11.2v1.6M12.8 8h-1.6M4.8 8H3.2M11 5l-1.1 1.1M6.1 9.9L5 11M11 11l-1.1-1.1M6.1 6.1L5 5" stroke="var(--accent-deep)" stroke-width="1.2" stroke-linecap="round"/></svg>
Babel
</span>
<span class="jb-pipe-arrow">β</span>
<span class="jb-pipe-node">
<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M4 3 L4 12 Q4 13.5 5.5 13.5" fill="none" stroke="var(--ink-soft)" stroke-width="1.4" stroke-linecap="round"/><path d="M12 3 L12 12 Q12 13.5 10.5 13.5" fill="none" stroke="var(--ink-soft)" stroke-width="1.4" stroke-linecap="round"/></svg>
Plain JS
</span>
</div>
<div class="jb-tabs" id="jbTabs">
<button class="jb-tab is-active" data-tab="1" type="button"><span class="jb-tab-num">1</span> No props</button>
<button class="jb-tab" data-tab="2" type="button"><span class="jb-tab-num">2</span> Props + children</button>
</div>
<div class="jb-panel is-visible" data-panel="1">
<div class="jb-code-compare">
<div class="jb-code-block">
<div class="jb-code-head">
<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M6 3 L2 8 L6 13" fill="none" stroke="var(--accent)" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/><path d="M10 3 L14 8 L10 13" fill="none" stroke="var(--accent)" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>
<span class="jb-code-name">JSX</span>
</div>
<pre><code><span class="tok-punc"><</span><span class="hb-tok tok-tag" data-map="type" tabindex="0" role="button" aria-pressed="false">Header</span><span class="tok-punc"> /></span></code></pre>
</div>
<div class="jb-code-block">
<div class="jb-code-head">
<svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="3.2" fill="none" stroke="var(--accent)" stroke-width="1.4"/><path d="M8 3.2v1.6M8 11.2v1.6M12.8 8h-1.6M4.8 8H3.2" stroke="var(--accent)" stroke-width="1.2" stroke-linecap="round"/></svg>
<span class="jb-code-name">Compiled</span>
</div>
<pre><code><span class="tok-tag">React</span><span class="tok-punc">.createElement(</span><span class="hb-tok tok-tag" data-map="type" tabindex="0" role="button" aria-pressed="false">Header</span><span class="tok-punc">, </span><span class="hb-tok tok-kw" data-map="null" tabindex="0" role="button" aria-pressed="false">null</span><span class="tok-punc">)</span></code></pre>
</div>
</div>
</div>
<div class="jb-panel" data-panel="2">
<div class="jb-code-compare">
<div class="jb-code-block">
<div class="jb-code-head">
<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M6 3 L2 8 L6 13" fill="none" stroke="var(--accent)" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/><path d="M10 3 L14 8 L10 13" fill="none" stroke="var(--accent)" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>
<span class="jb-code-name">JSX</span>
</div>
<pre><code><span class="tok-punc"><</span><span class="hb-tok tok-tag" data-map="type" tabindex="0" role="button" aria-pressed="false">Greeting</span> <span class="hb-tok" data-map="props" tabindex="0" role="button" aria-pressed="false"><span class="tok-attr">name</span><span class="tok-punc">=</span><span class="tok-punc">{</span><span class="tok-expr">user</span><span class="tok-punc">}</span> <span class="tok-attr">className</span><span class="tok-punc">=</span><span class="tok-str">"card"</span></span><span class="tok-punc">></span>
<span class="hb-tok" data-map="children" tabindex="0" role="button" aria-pressed="false">Hello!</span>
<span class="tok-punc"></</span><span class="hb-tok tok-tag" data-map="type" tabindex="0" role="button" aria-pressed="false">Greeting</span><span class="tok-punc">></span></code></pre>
</div>
<div class="jb-code-block">
<div class="jb-code-head">
<svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="3.2" fill="none" stroke="var(--accent)" stroke-width="1.4"/><path d="M8 3.2v1.6M8 11.2v1.6M12.8 8h-1.6M4.8 8H3.2" stroke="var(--accent)" stroke-width="1.2" stroke-linecap="round"/></svg>
<span class="jb-code-name">Compiled</span>
</div>
<pre><code><span class="tok-tag">React</span><span class="tok-punc">.createElement(</span>
<span class="hb-tok tok-tag" data-map="type" tabindex="0" role="button" aria-pressed="false">Greeting</span><span class="tok-punc">,</span>
<span class="hb-tok" data-map="props" tabindex="0" role="button" aria-pressed="false"><span class="tok-punc">{</span> <span class="tok-attr">name</span><span class="tok-punc">:</span> <span class="tok-expr">user</span><span class="tok-punc">,</span> <span class="tok-attr">className</span><span class="tok-punc">:</span> <span class="tok-str">"card"</span> <span class="tok-punc">}</span></span><span class="tok-punc">,</span>
<span class="hb-tok tok-str" data-map="children" tabindex="0" role="button" aria-pressed="false">"Hello!"</span>
<span class="tok-punc">)</span></code></pre>
</div>
</div>
</div>
<p class="jb-caption" id="jbCaption">Click any part of the JSX to see where Babel puts it.</p>
<div class="jb-takeaway"><b>Every JSX element</b> becomes a three-argument function call β type, props, children.</div>
</div>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Fraunces:wght@500;600&family=Inter:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet">
<script>
(function () {
var root = document.getElementById('jb');
if (!root) return;
/* --- dark mode detection: body attribute > cookie > postMessage > light --- */
function applyDark(dark) {
if (dark) root.setAttribute('data-theme', 'dark');
else root.removeAttribute('data-theme');
}
var bodyAttr = document.body.getAttribute('data-darkmode');
var dark;
if (bodyAttr === 'true') dark = true;
else if (bodyAttr === 'false') dark = false;
else {
var match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
applyDark(dark);
window.addEventListener('message', function (e) {
if (e.data && e.data.type === 'darkMode') applyDark(!!e.data.value);
});
/* --- tabs --- */
var tabs = root.querySelectorAll('.jb-tab');
var panels = root.querySelectorAll('.jb-panel');
var caption = root.querySelector('#jbCaption');
var defaultCaption = 'Click any part of the JSX to see where Babel puts it.';
function setTab(tabId) {
tabs.forEach(function (t) { t.classList.toggle('is-active', t.getAttribute('data-tab') === tabId); });
panels.forEach(function (p) { p.classList.toggle('is-visible', p.getAttribute('data-panel') === tabId); });
clearHighlight();
}
tabs.forEach(function (t) {
t.addEventListener('click', function () { setTab(t.getAttribute('data-tab')); });
});
/* --- click-to-map --- */
var captions = {
type: 'The tag name becomes the first argument β what to create.',
props: 'The attributes collapse into one object β the second argument.',
children: 'Whatever sits between the tags becomes the third argument.',
null: 'No attributes and no children, so Babel just passes null.'
};
var active = null;
function clearHighlight() {
active = null;
root.querySelectorAll('.hb-tok').forEach(function (el) {
el.classList.remove('is-active', 'is-dim');
el.setAttribute('aria-pressed', 'false');
});
caption.textContent = defaultCaption;
}
function setActive(key) {
active = (active === key) ? null : key;
var visiblePanel = root.querySelector('.jb-panel.is-visible');
var toks = visiblePanel.querySelectorAll('.hb-tok');
toks.forEach(function (el) {
var match = el.getAttribute('data-map') === active;
el.classList.toggle('is-active', !!active && match);
el.classList.toggle('is-dim', !!active && !match);
el.setAttribute('aria-pressed', (!!active && match) ? 'true' : 'false');
});
caption.textContent = active ? captions[active] : defaultCaption;
}
root.querySelectorAll('.hb-tok').forEach(function (el) {
el.addEventListener('click', function () { setActive(el.getAttribute('data-map')); });
el.addEventListener('keydown', function (e) {
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setActive(el.getAttribute('data-map')); }
});
});
})();
</script>π οΈ Summary
Term | Meaning |
|---|---|
JSX | JavaScript XML β lets you write HTML in React components |
Babel | A compiler that converts JSX and modern JS to browser-compatible JS |