π What is React?
React is a JavaScript library created by Facebook (now Meta) for building user interfaces (UIs), especially for single-page applications (SPAs). It is open-source and widely used in both industry and open-source projects.
React allows developers to create dynamic and responsive web applications by breaking down the UI into reusable components.
<div class="infographic-onlyjsreact" id="ojsr">
<style>
.infographic-onlyjsreact {
--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;
margin: 0 auto;
box-sizing: border-box;
background: transparent;
color: var(--ink);
font-family: var(--body-font);
}
.infographic-onlyjsreact[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #13171f;
--paper-alt: #1c212b;
--accent: #5b8def;
--accent-deep: #8fb4ff;
--accent-soft: #20293f;
--line: #2c313d;
}
.infographic-onlyjsreact * { box-sizing: border-box; }
.oj-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;
}
.oj-eyebrow::before { content: ""; width: 14px; height: 2px; background: var(--accent); display: inline-block; }
.oj-title {
font-family: var(--display-font); font-size: clamp(1.5rem, 4vw, 2.3rem);
margin: 0 0 0.55rem; line-height: 1.12; letter-spacing: -0.01em; text-align: center;
}
.oj-sub {
color: var(--ink-soft); font-size: 0.95rem; max-width: 560px; line-height: 1.55; margin: 0 auto 1.9rem;
text-align: center;
}
.oj-output-label {
font-family: var(--mono-font); font-size: 0.7rem; letter-spacing: 0.1em; text-transform: uppercase;
color: var(--ink-soft); text-align: center; margin: 0 0 0.7rem;
}
/* ===== Stepper + live card grid ===== */
.oj-stepper { display: flex; align-items: center; justify-content: center; gap: 0.9rem; margin-bottom: 1.1rem; }
.oj-step-btn {
width: 32px; height: 32px; border-radius: 50%; border: 1.5px solid var(--line); background: var(--paper-alt);
color: var(--ink); font-size: 1.1rem; line-height: 1; cursor: pointer; display: flex; align-items: center;
justify-content: center; transition: border-color 0.15s, background 0.15s;
}
.oj-step-btn:hover:not(:disabled) { border-color: var(--accent); background: var(--accent-soft); }
.oj-step-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.oj-step-btn:disabled { opacity: 0.35; cursor: default; }
.oj-step-count { font-family: var(--mono-font); font-size: 0.82rem; color: var(--ink-soft); min-width: 108px; text-align: center; }
.oj-step-count b { color: var(--ink); }
.oj-card-grid {
display: flex; flex-wrap: wrap; justify-content: center; gap: 0.6rem; padding: 1.1rem;
background: var(--paper-alt); border: 1px solid var(--line); border-radius: var(--radius); margin-bottom: 1.75rem;
}
.oj-card {
width: 92px; background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius);
padding: 0.7rem 0.4rem; text-align: center; animation: oj-card-in 0.25s ease;
}
@keyframes oj-card-in { from { opacity: 0; transform: translateY(4px) scale(0.94); } to { opacity: 1; transform: none; } }
.oj-card .oj-avatar {
width: 30px; height: 30px; border-radius: 50%; margin: 0 auto 0.45rem; display: flex; align-items: center;
justify-content: center; color: #fff; font-family: var(--display-font); font-weight: 600; font-size: 0.85rem;
}
.oj-card .oj-name { font-size: 0.74rem; font-weight: 600; margin: 0 0 0.1rem; }
.oj-card .oj-role { font-size: 0.66rem; color: var(--ink-soft); margin: 0; }
/* ===== Code panels ===== */
.oj-code-compare { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem; margin-bottom: 1.9rem; }
.oj-code-block { display: flex; flex-direction: column; }
.oj-code-head { display: flex; align-items: center; justify-content: center; gap: 0.45rem; margin-bottom: 0.4rem; }
.oj-code-head svg { width: 16px; height: 16px; flex-shrink: 0; }
.oj-code-name { font-size: 0.8rem; font-weight: 600; color: var(--ink); }
.oj-line-count {
font-family: var(--mono-font); font-size: 0.7rem; color: var(--ink-soft);
background: var(--paper-alt); border-radius: 100px; padding: 0.15rem 0.55rem;
}
.oj-line-bar { height: 4px; border-radius: 2px; background: var(--line); overflow: hidden; margin-bottom: 0.55rem; }
.oj-line-bar-fill { height: 100%; background: var(--accent); border-radius: 2px; transition: width 0.25s ease; }
.oj-code-block pre {
margin: 0; background: #0d0d10; border: 1px solid #24252d; border-radius: var(--radius);
padding: 0.9rem 1.75rem 0.9rem 1rem; overflow: auto; flex: 1; max-height: 260px;
}
.oj-code-block code { font-family: var(--mono-font); font-size: 0.72rem; line-height: 1.6; 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; }
@media (max-width: 640px) {
.oj-code-compare { grid-template-columns: 1fr; }
.oj-card { width: 84px; }
}
.oj-takeaway {
margin-top: 1.6rem; 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;
}
.oj-takeaway b { color: var(--accent-deep); }
@media (prefers-reduced-motion: reduce) {
.infographic-onlyjsreact *, .infographic-onlyjsreact *::before, .infographic-onlyjsreact *::after {
transition-duration: 0.001ms !important; animation-duration: 0.001ms !important;
}
}
</style>
<div class="oj-eyebrow">Scaling a UI</div>
<h1 class="oj-title">Only JS vs React</h1>
<p class="oj-sub">Add a teammate and watch what each approach costs you in code.</p>
<div class="oj-code-compare">
<div class="oj-code-block">
<div class="oj-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="oj-code-name">Only JS</span>
<span class="oj-line-count" id="ojVanillaLines">β lines</span>
</div>
<div class="oj-line-bar"><div class="oj-line-bar-fill" id="ojVanillaBar"></div></div>
<pre><code id="ojVanillaCode"></code></pre>
</div>
<div class="oj-code-block">
<div class="oj-code-head">
<svg viewBox="0 0 16 16" aria-hidden="true">
<g transform="translate(8,8)">
<ellipse rx="6.5" ry="2.6" fill="none" stroke="var(--accent)" stroke-width="1.2"/>
<ellipse rx="6.5" ry="2.6" fill="none" stroke="var(--accent)" stroke-width="1.2" transform="rotate(60)"/>
<ellipse rx="6.5" ry="2.6" fill="none" stroke="var(--accent)" stroke-width="1.2" transform="rotate(120)"/>
<circle r="1.3" fill="var(--accent)"/>
</g>
</svg>
<span class="oj-code-name">React</span>
<span class="oj-line-count" id="ojReactLines">β lines</span>
</div>
<div class="oj-line-bar"><div class="oj-line-bar-fill" id="ojReactBar"></div></div>
<pre><code id="ojReactCode"></code></pre>
</div>
</div>
<div class="oj-output-label">Output</div>
<div class="oj-stepper">
<button class="oj-step-btn" id="ojRemove" type="button" aria-label="Remove teammate">β</button>
<span class="oj-step-count" id="ojCount" aria-live="polite"><b>3</b> teammates</span>
<button class="oj-step-btn" id="ojAdd" type="button" aria-label="Add teammate">+</button>
</div>
<div class="oj-card-grid" id="ojCardGrid"></div>
<div class="oj-takeaway"><b>One component</b> defines the card β after that, every teammate is a single line.</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('ojsr');
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);
});
/* --- component-reuse simulator --- */
var names = ['Aria', 'Kabir', 'Zoe', 'Malik', 'Priya', 'Leo', 'Nadia', 'Theo'];
var roles = ['Designer', 'Engineer', 'PM', 'Support', 'Data', 'QA', 'Sales', 'Ops'];
var colors = ['#2563eb', '#1d4ed8', '#3b82f6', '#0ea5e9', '#0284c7', '#1e40af', '#4f8ef7', '#0369a1'];
var MIN = 1, MAX = names.length;
var n = 3;
var grid = root.querySelector('#ojCardGrid');
var countEl = root.querySelector('#ojCount');
var addBtn = root.querySelector('#ojAdd');
var removeBtn = root.querySelector('#ojRemove');
var vanillaCodeEl = root.querySelector('#ojVanillaCode');
var reactCodeEl = root.querySelector('#ojReactCode');
var vanillaLinesEl = root.querySelector('#ojVanillaLines');
var reactLinesEl = root.querySelector('#ojReactLines');
var vanillaBar = root.querySelector('#ojVanillaBar');
var reactBar = root.querySelector('#ojReactBar');
function esc(s) {
return String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
}
function openTag(name, attrs, selfClose) {
attrs = attrs || [];
var out = '<span class="tok-punc"><</span><span class="tok-tag">' + name + '</span>';
attrs.forEach(function (a) {
out += ' <span class="tok-attr">' + a.name + '</span><span class="tok-punc">=</span>';
out += a.expr
? '<span class="tok-punc">{</span><span class="tok-expr">' + a.value + '</span><span class="tok-punc">}</span>'
: '<span class="tok-str">"' + esc(a.value) + '"</span>';
});
out += selfClose ? ' <span class="tok-punc">/></span>' : '<span class="tok-punc">></span>';
return out;
}
function closeTag(name) {
return '<span class="tok-punc"></</span><span class="tok-tag">' + name + '</span><span class="tok-punc">></span>';
}
function buildVanillaLines(count) {
var lines = [openTag('div', [{ name: 'class', value: 'team' }])];
for (var i = 0; i < count; i++) {
lines.push(' ' + openTag('div', [{ name: 'class', value: 'card' }]));
lines.push(' ' + openTag('div', [{ name: 'class', value: 'avatar' }]) + esc(names[i][0]) + closeTag('div'));
lines.push(' ' + openTag('h3', []) + esc(names[i]) + closeTag('h3'));
lines.push(' ' + openTag('p', []) + esc(roles[i]) + closeTag('p'));
lines.push(' ' + closeTag('div'));
}
lines.push(closeTag('div'));
return lines;
}
function buildReactLines(count) {
var lines = [
'<span class="tok-kw">function</span> <span class="tok-tag">Card</span><span class="tok-punc">({ name, role }) {</span>',
' <span class="tok-kw">return</span> <span class="tok-punc">(</span>',
' ' + openTag('div', [{ name: 'className', value: 'card' }]),
' ' + openTag('div', [{ name: 'className', value: 'avatar' }]) +
'<span class="tok-punc">{</span><span class="tok-expr">name[0]</span><span class="tok-punc">}</span>' + closeTag('div'),
' ' + openTag('h3', []) + '<span class="tok-punc">{</span><span class="tok-expr">name</span><span class="tok-punc">}</span>' + closeTag('h3'),
' ' + openTag('p', []) + '<span class="tok-punc">{</span><span class="tok-expr">role</span><span class="tok-punc">}</span>' + closeTag('p'),
' ' + closeTag('div'),
' <span class="tok-punc">);</span>',
'<span class="tok-punc">}</span>',
'',
openTag('Team', [])
];
for (var i = 0; i < count; i++) {
lines.push(' ' + openTag('Card', [
{ name: 'name', value: names[i] },
{ name: 'role', value: roles[i] }
], true));
}
lines.push(closeTag('Team'));
return lines;
}
var maxLines = buildVanillaLines(MAX).length;
function render() {
/* card grid */
grid.innerHTML = '';
for (var i = 0; i < n; i++) {
var card = document.createElement('div');
card.className = 'oj-card';
var avatar = document.createElement('div');
avatar.className = 'oj-avatar';
avatar.style.background = colors[i];
avatar.textContent = names[i][0];
var nameEl = document.createElement('p');
nameEl.className = 'oj-name';
nameEl.textContent = names[i];
var roleEl = document.createElement('p');
roleEl.className = 'oj-role';
roleEl.textContent = roles[i];
card.appendChild(avatar);
card.appendChild(nameEl);
card.appendChild(roleEl);
grid.appendChild(card);
}
/* code panels */
var vLinesArr = buildVanillaLines(n);
var rLinesArr = buildReactLines(n);
vanillaCodeEl.innerHTML = vLinesArr.join('\n');
reactCodeEl.innerHTML = rLinesArr.join('\n');
vanillaLinesEl.textContent = vLinesArr.length + ' lines';
reactLinesEl.textContent = rLinesArr.length + ' lines';
vanillaBar.style.width = Math.round((vLinesArr.length / maxLines) * 100) + '%';
reactBar.style.width = Math.round((rLinesArr.length / maxLines) * 100) + '%';
/* stepper state */
countEl.innerHTML = '<b>' + n + '</b> teammate' + (n === 1 ? '' : 's');
addBtn.disabled = n >= MAX;
removeBtn.disabled = n <= MIN;
}
addBtn.addEventListener('click', function () { if (n < MAX) { n++; render(); } });
removeBtn.addEventListener('click', function () { if (n > MIN) { n--; render(); } });
render();
})();
</script>πΉ Key Highlights:
π Library, not a framework β React focuses only on the view layer of an application.
π§± Component-Based Architecture β UIs are built using independent, reusable blocks called components.
β‘ Efficient Rendering β Uses a virtual DOM to update only the parts of the page that change.
π Easily Integrates β Works well with other libraries or frameworks for routing, state management, etc.
π Where is React Used?
π Web applications like Facebook, Instagram, Netflix
π± Mobile apps using React Native
π₯οΈ Static websites or hybrid apps using Next.js
React has a rich ecosystem and is known for being fast, modular, and easy to scale, making it a go-to choice for modern front-end development.