Components: reusable building blocks for UI
Real interfaces repeat — a feed of cards, a list of rows, a grid of products. A component defines that repeating piece once, then stamps it out with different data. It's the DRY principle for UI.
The big idea
A component is a reusable piece of interface defined once (often as a function returning markup) and rendered many times with different data.
See it in code
A component is a piece of interface defined once. Here Card is a function that takes a name and role and returns the markup for one card. Call it once, and one card appears:
<div id="app"></div>
<script>
// a component: one function that returns markup
function Card(name, role) {
return '<div style="padding:12px;margin:8px 0;border:1px solid #ddd;border-radius:8px">'
+ '<strong>' + name + '</strong><br>'
+ '<span style="color:#64748b">' + role + '</span></div>';
}
document.getElementById("app").innerHTML = Card("Ada", "Engineer");
</script>Card("Ada", "Engineer") runs the function and drops its returned markup into the page. The card's shape lives in one place — the function.
The payoff is reuse. Call the same Card with different data and join the results — two cards from one definition:
<div id="app"></div>
<script>
function Card(name, role) {
return '<div style="padding:12px;margin:8px 0;border:1px solid #ddd;border-radius:8px">'
+ '<strong>' + name + '</strong><br>'
+ '<span style="color:#64748b">' + role + '</span></div>';
}
document.getElementById("app").innerHTML =
Card("Ada", "Engineer") + Card("Grace", "Designer");
</script>Same function, different arguments, two cards. Notice you never rewrote the card markup — you reused it.
Real pages render lists of data, so let the array do the calling. team.map(...) runs Card once per member and joins the results — three cards, still one definition:
<div id="app"></div>
<script>
// a component: one function that returns markup
function Card(name, role) {
return '<div style="padding:12px;margin:8px 0;border:1px solid #ddd;border-radius:8px">'
+ '<strong>' + name + '</strong><br>'
+ '<span style="color:#64748b">' + role + '</span></div>';
}
const team = [["Ada", "Engineer"], ["Grace", "Designer"], ["Alan", "Writer"]];
document.getElementById("app").innerHTML =
team.map(function (m) { return Card(m[0], m[1]); }).join("");
</script>One Card definition produced three cards — change the component once and all three update. That's exactly what React, Vue, and Svelte formalize: components take in data (props) and return UI, so you build big pages from small, reusable pieces.
Define once, reuse with parameters — you've seen this exact idea as functions in Python and spawn_wave() in the game course. Components apply it to interface: a unit of UI you can compose, test, and fix in a single place. It's the same principle wearing a different hat.
Try it yourself
Add a fourth team member and watch a fourth card appear with no new markup. Then give Card a third parameter (like an emoji avatar) and use it inside the returned string.
The common mistake
Copy-pasting the same markup instead of making a component. Duplication means fixing the same bug in five places and drift between copies. The moment you write similar markup twice, that's the signal to extract a component.
What it unlocks
Components compose your HTML, are rendered through the DOM, and apply the reuse principle behind functions.