JSON and HTML

See how a JSON array or object can be turned into live, styled HTML on a page, without a server round trip for every update.

From Data to DOM

JSON only describes the shape of data — it has no idea what a webpage looks like. Turning it into something a visitor can see is entirely your job in JavaScript: you read the array or object, decide what markup represents each piece, and insert that markup into the page. This pattern shows up anywhere a page renders a variable number of items — product grids, comment threads, search results, notification lists.

Building HTML from an Array of Objects

The most common case is an array of similarly-shaped objects that should each become one repeated chunk of markup. The idiomatic approach is to map() the array into an array of HTML strings, join them into one string, and assign that string to an element's innerHTML in a single operation.

Rendering a product list

<!DOCTYPE html>
<html>
<body>

<h2>Result</h2>
<ul id="product-list"></ul>

<script>
const products = [
  { name: 'Keyboard', price: 49.99 },
  { name: 'Mouse', price: 19.99 },
  { name: 'Monitor', price: 199.99 }
];

const container = document.getElementById('product-list');
container.innerHTML = products
  .map(p => `<li>${p.name} - $${p.price.toFixed(2)}</li>`)
  .join('');
</script>

</body>
</html>

Building HTML from a Single Object

Rendering one nested object — like a user profile — usually means reaching into sub-objects that may or may not exist. Optional chaining (?.) and the nullish coalescing operator (??) let you supply a sensible fallback instead of letting a missing address field crash the whole render with 'Cannot read properties of undefined'.

Rendering a nested profile object

<!DOCTYPE html>
<html>
<body>

<h2>Result</h2>
<div id="profile"></div>

<script>
const profile = {
  name: 'Ana Torres',
  title: 'Backend Engineer',
  address: { city: 'Lisbon', country: 'Portugal' }
};

function renderProfile(person) {
  const city = person.address?.city ?? 'Unknown city';
  const country = person.address?.country ?? 'Unknown country';
  return `
    <div class="card">
      <h3>${person.name}</h3>
      <p>${person.title ?? 'No title provided'}</p>
      <p>${city}, ${country}</p>
    </div>
  `;
}

document.getElementById('profile').innerHTML = renderProfile(profile);
</script>

</body>
</html>
  • Never inject untrusted JSON string fields into innerHTML unescaped — use textContent for plain text, or escape HTML-sensitive characters first.
  • Build the whole markup string (or fragment) off-screen, then insert it once, instead of touching the DOM inside a loop.
  • Give repeated elements a stable identifier (like a data-id attribute from the JSON) so you can find and update a single item later.
  • Keep the mapping function pure — given the same object, it should always produce the same markup, which makes it easy to test.

Updating the DOM Efficiently

Rebuilding an entire innerHTML string works fine for small lists, but for large or frequently-changing lists it forces the browser to destroy and recreate every element, which discards any event listeners or input focus. Building nodes directly with the DOM API and batching them into a DocumentFragment avoids that cost — the fragment lives off-screen and only touches the real page once, on append.

Rendering with createElement and a fragment

<!DOCTYPE html>
<html>
<body>

<h2>Result</h2>
<ul id="product-list"></ul>

<script>
const items = [
  { name: 'Keyboard', price: 49.99 },
  { name: 'Mouse', price: 19.99 }
];

const list = document.getElementById('product-list');
const fragment = document.createDocumentFragment();

items.forEach(item => {
  const li = document.createElement('li');
  li.textContent = `${item.name} - $${item.price.toFixed(2)}`;
  fragment.appendChild(li);
});

list.appendChild(fragment);
</script>

</body>
</html>
ApproachReadabilityPerformance on large listsXSS safety
innerHTML + map().join()High — very conciseLower — re-parses full markupLow unless values are escaped
createElement + textContentLower — more codeHigher — targeted DOM updatesHigh — textContent never parses HTML
Note: If a JSON field ever contains attacker-controlled text (a username, a comment body, a search term echoed back), putting it straight into innerHTML is a textbook cross-site scripting hole. Use textContent, or an escaping helper, for anything that didn't come from your own trusted server logic.
Note: For quick lists without per-item interactivity, the map().join() + innerHTML pattern is genuinely the fastest to write and read. Reach for manual DOM building mainly when you need to attach event listeners to individual items or update them independently later.

Exercise: JSON HTML

What is a common way to display JSON data inside an HTML page?