DEV Community

Michael Lip
Michael Lip

Posted on • Originally published at zovo.one

Generating HTML Tables Is a Solved Problem (Stop Writing Them by Hand)

I used to write HTML tables by hand. Every <tr>, every <td>, every closing tag, every colspan attribute. It is the most tedious part of HTML authoring, and there is zero reason to do it manually when you know the data.

A 10-row, 5-column table is 50 cells. That is 50 <td> tags, 50 closing </td> tags, 10 <tr> tags, 10 closing </tr> tags, plus the <table>, <thead>, <tbody> wrappers. Around 130 lines of markup for something that took 2 minutes to conceive.

The markdown approach

Markdown tables are the fastest way to express tabular data:

| Name    | Role      | Team     |
|---------|-----------|----------|
| Alice   | Engineer  | Platform |
| Bob     | Designer  | Product  |
| Charlie | PM        | Growth   |
Enter fullscreen mode Exit fullscreen mode

Clean, readable, and most markdown processors convert them to proper HTML tables. But markdown tables have serious limitations.

You cannot merge cells (colspan/rowspan). You cannot nest elements inside cells. You cannot style individual cells. You cannot add a caption. For documentation and README files, markdown tables are perfect. For anything more complex, you need HTML.

What a proper HTML table looks like

<table>
  <caption>Team Directory</caption>
  <thead>
    <tr>
      <th scope="col">Name</th>
      <th scope="col">Role</th>
      <th scope="col">Team</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Alice</td>
      <td>Engineer</td>
      <td>Platform</td>
    </tr>
  </tbody>
</table>
Enter fullscreen mode Exit fullscreen mode

The semantic elements matter. <thead> and <tbody> are not just organizational -- they affect how screen readers announce the table. <th scope="col"> tells assistive technology that the cell is a header for its column. <caption> provides a title that is programmatically associated with the table.

Skipping these semantic elements is an accessibility failure. A sighted user sees a table and understands it visually. A screen reader user depends on these elements to navigate and understand the table structure.

Responsive tables are still painful

Tables on mobile are a solved problem with multiple bad solutions and no perfect one.

Horizontal scroll. Wrap the table in a div with overflow-x: auto. The table keeps its layout and the user scrolls horizontally. Simple, but horizontal scrolling is a terrible UX on touch devices.

Stacked layout. At small screens, use CSS to display each row as a card with cells stacked vertically. Use data-label attributes to show column headers next to each cell. Better UX, but complex CSS and the visual relationship between rows is lost.

Column hiding. Hide less important columns at smaller breakpoints. Pragmatic, but you are hiding data.

Sticky first column. Keep the first column visible and scroll the rest horizontally. Works well for comparison tables.

There is no single solution. The right approach depends on the table's content and purpose.

CSV to table conversion

Most real-world table data starts as a CSV or spreadsheet. Manually converting CSV rows to HTML is exactly the kind of repetitive task that should be automated:

function csvToTable(csv) {
  const rows = csv.split('\n').map(row => row.split(','));
  const header = rows[0];
  const body = rows.slice(1);

  let html = '<table>\n<thead>\n<tr>\n';
  header.forEach(h => html += `  <th>${h.trim()}</th>\n`);
  html += '</tr>\n</thead>\n<tbody>\n';
  body.forEach(row => {
    html += '<tr>\n';
    row.forEach(cell => html += `  <td>${cell.trim()}</td>\n`);
    html += '</tr>\n';
  });
  html += '</tbody>\n</table>';
  return html;
}
Enter fullscreen mode Exit fullscreen mode

But this does not handle quoted fields containing commas, escaped quotes, or multiline cells. Proper CSV parsing is surprisingly complex.

The generator approach

I built a table generator at zovo.one/free-tools/table-generator that lets you input data in a spreadsheet-like grid or paste CSV/TSV data, then generates clean, semantic HTML with proper thead, tbody, th with scope attributes, and optional caption. It also outputs markdown table syntax if that is what you need. No more hand-writing 130 lines of markup for a simple data table.

I'm Michael Lip. I build free developer tools at zovo.one. 500+ tools, all private, all free.

Top comments (0)