Convert JSON to HTML Table
The most common use case is converting a JSON array of objects into an HTML <table> — each object becomes a row, each key becomes a column header. JavaScript can do this in the browser at runtime; Python can generate the HTML server-side. Both approaches are 15–20 lines of code without any library.
Paste JSON into Jsonic's formatter to validate it before rendering as a table.
Open JSON FormatterBasic JSON array to HTML table (JavaScript)
Start with a plain array of objects. The function extracts headers from the first object's keys, builds a <thead> row, then maps each object to a <tr> in the <tbody>.
const data = [
{ name: "Alice", age: 30, city: "New York" },
{ name: "Bob", age: 25, city: "London" },
{ name: "Carol", age: 35, city: "Tokyo" },
]
function jsonToTable(data) {
if (!data.length) return '<p>No data</p>'
// Extract headers from the first object
const headers = Object.keys(data[0])
const headerRow = headers.map(h => `<th>${h}</th>`).join('')
const bodyRows = data.map(row =>
`<tr>${headers.map(h => `<td>${row[h] ?? ''}</td>`).join('')}</tr>`
).join('')
return `
<table>
<thead><tr>${headerRow}</tr></thead>
<tbody>${bodyRows}</tbody>
</table>`
}
document.getElementById('output').innerHTML = jsonToTable(data)This produces a table with headers name, age, city and one row per object. The ?? '' operator safely coerces missing or null values to an empty string.
| name | age | city |
|---|---|---|
| Alice | 30 | New York |
| Bob | 25 | London |
| Carol | 35 | Tokyo |
Parse a JSON string first
When data arrives from an API or file, it's typically a JSON string. Call JSON.parse() before passing it to jsonToTable().
const jsonString = '[{"id":1,"product":"Widget","price":9.99},{"id":2,"product":"Gadget","price":29.99}]'
const data = JSON.parse(jsonString)
document.getElementById('output').innerHTML = jsonToTable(data)If JSON.parse() throws a SyntaxError, the JSON is malformed. Use Jsonic's formatter to spot and fix errors before rendering.
Auto-detect all unique headers (union of all keys)
Real-world JSON arrays are often sparse — not every object has every key. Collecting the union of all keys across all rows ensures no column is silently dropped.
// If objects have different keys, collect all unique keys across all rows
function getAllHeaders(data) {
const keys = new Set()
data.forEach(row => Object.keys(row).forEach(k => keys.add(k)))
return [...keys]
}
function jsonToTable(data) {
const headers = getAllHeaders(data)
const headerRow = headers.map(h => `<th>${h}</th>`).join('')
const bodyRows = data.map(row =>
`<tr>${headers.map(h => `<td>${row[h] ?? ''}</td>`).join('')}</tr>`
).join('')
return `<table><thead><tr>${headerRow}</tr></thead><tbody>${bodyRows}</tbody></table>`
}Using a union of keys handles sparse JSON arrays where objects don't all have the same keys. Missing cells are rendered as empty <td> elements.
Handle nested objects (flatten or stringify)
If a JSON value is itself an object or array, rendering it directly produces [object Object] in the cell. A formatCell helper detects nested values and stringifies them.
function formatCell(value) {
if (value === null || value === undefined) return ''
if (typeof value === 'object') return JSON.stringify(value) // or flatten
return String(value)
}
function jsonToTable(data) {
const headers = Object.keys(data[0])
const headerRow = headers.map(h => `<th>${h}</th>`).join('')
const bodyRows = data.map(row =>
`<tr>${headers.map(h => `<td>${formatCell(row[h])}</td>`).join('')}</tr>`
).join('')
return `<table><thead><tr>${headerRow}</tr></thead><tbody>${bodyRows}</tbody></table>`
}For deeply nested data, consider flattening the JSON first with a utility like flat (npm) so each leaf key becomes its own column. Stringifying is simpler but makes cells harder to read.
Add CSS classes for styling
Pass options to control the table class and enable zebra-stripe rows. This makes it easy to apply existing CSS design systems without editing the generated markup.
function jsonToTable(data, { tableClass = 'data-table', headerClass = '' } = {}) {
const headers = Object.keys(data[0])
const headerRow = headers.map(h => `<th class="${headerClass}">${h}</th>`).join('')
const bodyRows = data.map((row, i) =>
`<tr class="${i % 2 === 0 ? 'even' : 'odd'}">${headers.map(h =>
`<td>${formatCell(row[h])}</td>`).join('')}</tr>`
).join('')
return `<table class="${tableClass}"><thead><tr>${headerRow}</tr></thead><tbody>${bodyRows}</tbody></table>`
}Basic CSS to style the output:
.data-table { border-collapse: collapse; width: 100%; }
.data-table th, .data-table td { border: 1px solid #ddd; padding: 8px; text-align: left; }
.data-table thead tr { background-color: #f2f2f2; }
.data-table tr.odd { background-color: #fafafa; }| Option | Default | Effect |
|---|---|---|
tableClass | 'data-table' | CSS class on <table> |
headerClass | '' | CSS class on each <th> |
| Row index parity | automatic | Adds even / odd class to each <tr> |
Python: generate an HTML table from JSON
Server-side HTML generation is common in Django, Flask, and FastAPI. This pure-Python function reads a JSON file and returns a complete <table> string without any third-party dependencies.
import json
def json_to_html_table(data, table_class="data-table"):
if not data:
return "<p>No data</p>"
headers = list(data[0].keys())
header_cells = "".join(f"<th>{h}</th>" for h in headers)
rows = ""
for row in data:
cells = "".join(f"<td>{row.get(h, '')}</td>" for h in headers)
rows += f"<tr>{cells}</tr>\n"
return (
f'<table class="{table_class}">'
f"<thead><tr>{header_cells}</tr></thead>"
f"<tbody>{rows}</tbody>"
f"</table>"
)
with open("data.json") as f:
data = json.load(f)
html = json_to_html_table(data)
print(html)row.get(h, '') safely returns an empty string for any key missing from a given row, making the function robust against sparse JSON arrays. You can embed the returned string in a Jinja2 template with {{ html | safe }} to prevent double-escaping.
Using pandas (Python, easiest for DataFrames)
If the data is already in a pandas DataFrame — or if you're doing any data analysis before rendering — DataFrame.to_html() is the fastest path to a styled table.
import pandas as pd
import json
with open("data.json") as f:
data = json.load(f)
df = pd.DataFrame(data)
# Built-in HTML export
html = df.to_html(index=False, classes="data-table", border=0)
print(html)pd.DataFrame.to_html() generates a full <table> with <thead> and <tbody>. Pass index=False to omit the DataFrame row numbers. Pass classes to add CSS class names. Additional options include escape=False to render HTML inside cells and na_rep to control how NaN values appear.
| Approach | Language | Dependencies | Best for |
|---|---|---|---|
| Manual template string | JavaScript | None | Browser runtime, no build step |
| JSX map | React / TypeScript | React | Component-based UIs with state |
| Pure Python function | Python | None | Server-side HTML generation |
DataFrame.to_html() | Python | pandas | Data analysis pipelines, notebooks |
Frequently asked questions
How do I render a JSON array as a table in React?
Map the data array to <tr> elements inside a JSX <table>. Extract headers with Object.keys(data[0]) and map them to <th> elements in <thead>. Each row maps to a <tr> with <td> for each header key. This gives full React control over styles and events.
What happens if my JSON objects have different keys?
Use a union of all keys across all objects: iterate every row and add all keys to a Set. Missing values for a given row render as empty cells using row[key] ?? ''.
How do I handle nested JSON objects in a table cell?
Stringify nested objects with JSON.stringify(value) to display them as a readable string, or flatten the JSON before rendering. Rendering raw nested objects will display [object Object] in the cell if you don't handle them explicitly.
Can I add sorting to the generated HTML table?
Yes. Add click handlers to <th> elements that re-sort the data array and re-render the table. Alternatively, use a library like DataTables.js, which adds sorting, filtering, and pagination to any <table> element with a single line of JavaScript.
How do I convert JSON to a table in Excel instead?
Convert JSON to CSV first (flatten the array into comma-separated rows), then open the CSV file in Excel. Alternatively, use the xlsx library (npm) in Node.js to write a .xlsx file directly from a JSON array: const ws = xlsx.utils.json_to_sheet(data); xlsx.utils.book_append_sheet(wb, ws, 'Sheet1').
Is there a library that converts JSON to an HTML table automatically?
Yes. json-to-table, tabulator.js, and ag-grid all convert JSON arrays to tables with minimal code. For quick one-off use, the 15-line function in this guide is usually simpler. For production tables with sorting, filtering, and pagination, a library is worth the dependency.
Validate JSON before converting
A single syntax error in your JSON will cause JSON.parse() to throw and your table to render blank. Paste your JSON into Jsonic's formatter to catch and fix errors before you convert.