SKU // 122

JSON HTML

JSON data in a variable is only useful if people can see it. This lesson turns JSON into things on a web page: a sentence, a list, a table, and a page that loads its own data. There is no separate HTML section in this course, so the few page tools you need are explained right here.

// The Page Is Something JavaScript Can Change

A web page is made of elements: paragraphs, lists, table rows. JavaScript can find an element and change what is inside it. Three tools cover almost everything in this lesson:

Tool Does
document.getElementById("out")finds the element whose id is out
element.textContent = "..."replaces what is inside it with plain text
document.createElement("li")makes a new element, not yet on the page
parent.appendChild(child)puts the new element on the page, inside the parent
element.innerHTML = "..."replaces what is inside with text that is read as HTML markup

The buttons in this lesson open a small page in the editor (the Result pane shows what the page looks like). The output boxes show the text that page displays.

// One Value into One Element

<p id="out"></p>

<script>
  const data = JSON.parse('{"name":"Ava","grade":10}');
  document.getElementById("out").textContent = data.name + " is in grade " + data.grade;
</script>
Ava is in grade 10

// An Array into a List

For an array, make one new element per item and add each to the page:

<ul id="list"></ul>

<script>
  const students = JSON.parse('[{"name":"Ava","grade":10},{"name":"Ben","grade":11}]');
  const list = document.getElementById("list");
  for (const s of students) {
    const li = document.createElement("li");
    li.textContent = s.name + " (grade " + s.grade + ")";
    list.appendChild(li);
  }
</script>
Ava (grade 10) Ben (grade 11)

// An Array into a Table

For something with many pieces, such as table rows, it is often easier to build the markup as one string with map and join, then set innerHTML once:

<table id="t" border="1" cellpadding="4"></table>

<script>
  const rows = JSON.parse('[{"name":"Pen","price":2.5},{"name":"Notebook","price":4.75}]');
  const html = rows.map(r => "<tr><td>" + r.name + "</td><td>$" + r.price.toFixed(2) + "</td></tr>").join("");
  document.getElementById("t").innerHTML = html;
</script>
Pen $2.50 Notebook $4.75

// textContent or innerHTML?

The two behave differently when the data contains angle brackets. textContent always treats it as plain text. innerHTML reads it as markup:

<p id="a"></p>
<p id="b"></p>

<script>
  const data = JSON.parse('{"comment":"<b>hi</b>"}');
  document.getElementById("a").textContent = data.comment;
  document.getElementById("b").innerHTML = data.comment;
</script>
<b>hi</b> hi
Never put someone else's text into innerHTML
If the JSON contains text typed by users (comments, names, messages), innerHTML would let a user slip their own HTML and scripts onto your page. That is a real attack. Use textContent, or build elements with createElement, for any data you did not write yourself. Save innerHTML for markup you control.

// A Page That Loads Its Own Data

Put it together: fetch the JSON, then fill in the page. Start with a "Loading..." message so the page is never blank, and replace it when the data arrives:

<h3>Active students</h3>
<ul id="list"><li>Loading...</li></ul>

<script>
  fetch("students.json")
    .then(response => response.json())
    .then(students => {
      const list = document.getElementById("list");
      list.innerHTML = "";
      for (const s of students.filter(s => s.active)) {
        const average = s.scores.reduce((a, b) => a + b, 0) / s.scores.length;
        const li = document.createElement("li");
        li.textContent = s.name + ": " + average.toFixed(1);
        list.appendChild(li);
      }
    });
</script>
Active students Ava: 85.0 Ben: 84.3 Dee: 86.7

// Show a Message When It Fails

Real pages must handle the case where the data does not arrive. Check response.ok, and write a friendly message into the page instead of leaving "Loading..." forever:

<p id="status">Loading...</p>

<script>
  fetch("missing.json")
    .then(response => {
      if (!response.ok) {
        throw new Error("Could not load data (" + response.status + ")");
      }
      return response.json();
    })
    .then(data => {
      document.getElementById("status").textContent = "Loaded";
    })
    .catch(error => {
      document.getElementById("status").textContent = error.message;
    });
</script>
Could not load data (404)
Put your script after the elements
A script that looks up an element by id must come after that element in the page, or the element does not exist yet when the script runs. That is why every example here puts the <script> last.

// Quick Check

Which is safest for showing text that a user typed?

  1. element.innerHTML = text
  2. element.textContent = text
  3. document.write(text)
  4. They are all equally safe
Show answer
B. textContent treats everything as plain text, so any HTML in it cannot run.

Why start a data-driven page with a "Loading..." message?

Show answer
The data takes time to arrive. Without a message the page looks empty or broken. Replace it when the data loads, and replace it with an error message if the load fails.

What is wrong?

const list = document.getElementById("list");
const li = document.createElement("li");
li.textContent = "Ava";
Show answer
The new li is never added to the page. It needs list.appendChild(li); as well.

// Try It

  1. Click Open Playground and look at the Result pane. Change one name in the JSON and run it again
  2. Make the Playground show a table of the three products from the JSON instead of a list
  3. Add a heading above the list that shows how many students there are
  4. Replace textContent with innerHTML and put <b> tags in a name. What changes?
Last updated: Oct 12, 2026, 11:00 AM ET