JSONToonPro
HTML table generator

JSON to HTML Table Converter

Convert JSON arrays to clean HTML table code in one click. All property keys become column headers, every array item becomes a row, and you can include optional CSS, a custom class name, and download a ready-to-use HTML file, entirely in your browser.

100% client sideOptional CSSDownload HTML
Class
3 rows × 5 cols
Input/ JSON
385 chars23 lines
Output/ HTML
585 chars34 lines

Semantic Table Markup

A correct HTML table is more than rows of cells. The elements carry meaning that browsers, screen readers, and search engines all rely on, and using the right ones costs nothing extra.

  • table wraps the whole grid and declares that this is tabular data.
  • caption gives the table a title. It must be the first child of table, and it is announced before the content.
  • thead holds the header row. Browsers repeat it across pages when printing.
  • tbody holds the data rows. It is inserted automatically if you omit it, so writing it explicitly keeps your source matching the rendered DOM.
  • th marks a header cell, styled bold and centred by default and, more importantly, treated as a label for the cells it governs.
  • td marks a data cell.
  • tfoot holds totals and summary rows, and may appear before or after tbody in the source.

Side by Side Example

A pricing table generated from a JSON array.

JSON input

[
{ "plan": "Starter",
"seats": 3,
"monthly": "£9",
"note": "Fair use & basic support" },
{ "plan": "Team",
"seats": 25,
"monthly": "£39",
"note": "Priority support" },
{ "plan": "Scale",
"seats": 250,
"monthly": "£149",
"note": "SLA <4h response" }
]

HTML output

<table>
<caption>Pricing plans</caption>
<thead>
<tr>
<th scope="col">plan</th>
<th scope="col">seats</th>
<th scope="col">monthly</th>
<th scope="col">note</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Starter</th>
<td>3</td>
<td>&pound;9</td>
<td>Fair use &amp; basic support</td>
</tr>
<tr>
<th scope="row">Scale</th>
<td>250</td>
<td>&pound;149</td>
<td>SLA &lt;4h response</td>
</tr>
</tbody>
</table>

The ampersand and the less-than sign in the note column are escaped. Without that, the last row would swallow everything after &lt;4h as an unknown tag.

Accessibility Requirements

Screen readers navigate tables cell by cell and announce the relevant headers as they go. That only works if the markup says which headers apply.

RequirementHowWhy it matters
Header directionscope="col" or scope="row" on every thTells assistive tech which cells a header labels
Table titleA caption elementAnnounced first, so a user knows what they entered
Row headersFirst cell of each row as th, not tdGives every data cell a row label as well as a column one
Complex headersheaders and id attributesNeeded when a cell has more than one applicable header
No layout tablesUse CSS grid or flexbox for layoutA layout table is announced as data and is meaningless read aloud
role="presentation"Only on unavoidable legacy layout tablesStrips table semantics so it is not announced as a grid

Using a table for page layout was standard practice twenty years ago and is now simply wrong. A screen reader announces a five column table and starts reading coordinates, which is a genuinely disorienting experience. CSS handles layout, tables handle data.

Escaping Before Insertion

Any value that came from a user, an upload, or an external API is untrusted, and inserting it into HTML without escaping is a cross site scripting vulnerability.

The five characters and the safe pattern

& -> &amp; < -> &lt; > -> &gt;
" -> &quot; ' -> &#39;
 
// Unsafe: parses and executes the value as markup
cell.innerHTML = value;
 
// Safe: inserts the value as text, whatever it contains
cell.textContent = value;

Escape the ampersand first, otherwise you will double escape the entities you just produced. Framework templating in React, Vue, Angular, and most server side template engines escapes interpolated values by default, so the danger is concentrated in the escape hatches: dangerouslySetInnerHTML, v-html, and any raw string concatenation. Escape attribute values too, since a stray quote inside an attribute lets an attacker close it and add another one.

Responsive Strategies for Wide Tables

Tables do not reflow. A ten column table on a 375 pixel screen has to give somewhere, and there are two approaches that work.

Horizontal scroll on a wrapper

<div class="table-wrap" role="region"
aria-label="Pricing plans" tabindex="0">
<table> ... </table>
</div>
 
.table-wrap { overflow-x: auto; }
table { min-width: 640px; }

The wrapper, not the table, gets the overflow. The tabindex makes the scrollable region reachable by keyboard, which is a requirement rather than a nicety, and the label tells a screen reader what the region contains. This preserves the table semantics completely and is the right default.

The alternative is a card layout below a breakpoint, where each row becomes a stacked block and the column name is shown as a label using a data attribute and a CSS pseudo element. It reads better on a phone for tables of five or six columns, and it is worse for anything where comparing values across rows is the point, since the alignment that made comparison easy is gone.

Light Styling and Where the Output Goes

Zebra striping and a sticky header

table { border-collapse: collapse; width: 100%; }
th, td { padding: 8px 12px; text-align: left; }
tbody tr:nth-child(even) { background: #fafbfc; }
thead th { position: sticky; top: 0; background: #fff; }
td.num { text-align: right;
font-variant-numeric: tabular-nums; }

Right align numeric columns and use tabular figures so the digits line up in columns. It makes scanning for magnitude far easier and it is one line of CSS.

Generated tables end up in a few predictable places. HTML email is the most demanding, since many clients support only inline styles and a limited CSS subset, so keep the markup simple and put styles on the elements. Documentation sites, CMS pages, and static site builds are the common cases, and there a semantic table with a stylesheet is ideal. Internal reports and exported dashboards round out the list.

Tables travel between formats constantly. Check the full converter collection for JSON to Markdown when the destination is a README rather than a web page, JSON to CSV when someone wants it in a spreadsheet, and JSON to Excel for a formatted workbook.

How to convert JSON to an HTML table

Three steps
01

Paste or upload JSON

Add a JSON array of objects to the input panel. Use the sample button to load example user data.

02

Set table options

Choose header row, pretty HTML formatting, optional CSS styles, and an optional CSS class name.

03

Copy or download HTML

The HTML table code updates live. Copy it or download a complete .html file.

Built for web developers

Paste any JSON API response and get production-ready HTML table code in seconds, no manual column mapping, no server needed.

100% client side

No upload, no server. All conversion happens in your browser.

Live conversion

HTML output updates instantly as you type or change options.

Smart headers

Keys from all array items are merged so sparse arrays produce full-width tables.

CSS included

Optional style block adds clean table styling ready to paste into any page.

Custom class

Add a CSS class name to the table element for easy stylesheet targeting.

Download HTML

Export a complete .html file with your table and optional styles.

Frequently asked questions

6 answers
Paste a JSON array of objects into the input panel. The tool extracts all property keys as table headers and each array item as a row. The HTML output is generated instantly in the right panel.

Generate HTML Tables from JSON Arrays

This tool takes any JSON array of objects and builds a semantic HTML table with thead, tbody, th, and td elements. Keys are collected from all objects so even sparse arrays produce correctly aligned columns. Nested objects are serialised to JSON strings inside the cell. Enable the CSS option to include a basic style block, or add your own class name to target the table with an external stylesheet.

More JSON Tools