How do I make an HTML table from a list of values?
Write one row per line with the cells separated by commas (or paste a block of cells copied from a spreadsheet), and click Generate. Each line becomes a <tr>, each value becomes a cell, and with First row is a header ticked (the default) the first line's cells become <th> headings. Copy the result straight into your page.
Steps
- Type or paste your rows, for example from a CSV file or straight from a spreadsheet.
- Leave First row is a header ticked if the first line holds column names; untick it if every line is data.
- Click Generate.
- Click Copy and paste the markup into your HTML.
Worked example
Input:
Plan,Price,Users
Starter,$9,1
Team,$29,5
Output:
<table>
<tr>
<th>Plan</th>
<th>Price</th>
<th>Users</th>
</tr>
<tr>
<td>Starter</td>
<td>$9</td>
<td>1</td>
</tr>
<tr>
<td>Team</td>
<td>$29</td>
<td>5</td>
</tr>
</table>
Spaces around each value are trimmed, so Starter , $9 gives the same cells as Starter,$9. Spaces inside double quotes are kept.
How your input is interpreted
| Input pattern | Result |
|---|---|
A trailing comma, as in R&D,0, |
An extra empty cell at the end of that row |
| A blank line between rows | A row with one empty cell |
| Blank lines at the very start or end | Ignored |
| Rows with different numbers of values | Kept as-is; rows come out ragged |
"5, or more" in quotes |
One cell, 5, or more |
"say ""hi""" |
One cell, say "hi" (doubled quotes become one) |
5" screen (a quote in the middle of a value) |
Kept as a literal " |
| A quoted value with no closing quote | An error naming the line where it starts |
| Tab-separated text from a spreadsheet | Split on tabs, one cell per spreadsheet cell |
R&D <beta> |
Escaped to R&D <beta> |
The ragged-row behaviour is worth checking. Browsers will render a row with fewer cells than the others, but the right-hand side of that row is left empty, and table borders look uneven. Add the missing commas so every line has the same number of values.
What the generated markup leaves out
The output is deliberately minimal: <table>, <tr>, <th> and <td>. For a data table that's accessible and easy to style, it's worth adding a few things by hand:
<caption>right after<table>, giving the table a title that screen readers announce.<thead>and<tbody>around the header row and the data rows. Browsers insert a<tbody>automatically, but writing both makes CSS and JavaScript selectors predictable.scope="col"on each header cell, so assistive technology knows which cells it labels.- A class on the table for your stylesheet, since there's no styling at all.
The W3C's tables tutorial explains caption and header associations with examples, and MDN's <table> reference covers every related element. If tables are new to you, the HTML lessons start with the basic structure.
When to use an HTML table at all
Tables are for tabular data: rows and columns where both directions mean something, like a price list, a schedule or a comparison. Don't use one for page layout. Layout tables confuse screen readers and are hard to make responsive; CSS grid and flexbox do that job. The one common exception is HTML email, where many mail clients still handle tables more reliably than modern CSS.
Checking and tidying the result
Paste the generated markup into the HTML viewer to see it rendered before it goes into your page. Without CSS it will look plain, with no borders, which is normal. When you're done editing, the HTML minifier strips the indentation if you want compact markup.
Need dummy rows to test a layout? The random CSV generator produces comma-separated data you can paste straight in.
Privacy and limits
The conversion runs in your browser with a few lines of JavaScript; your data isn't sent anywhere. There's no row or column limit in the code, though very large tables are easier to manage in a spreadsheet or generated by your server-side code. The tool doesn't merge cells (colspan, rowspan) or sort rows; for those, edit the markup after generating it. A line break inside a quoted value is kept as-is in the cell, where browsers show it as a space, so add a <br> by hand if you want a visible break.
Last updated