Editable HTML table builder

Set up the columns, fill in the rows, copy the HTML. What comes out is one self-contained file whose cells can be typed into and whose columns sort.

Editable table builder4 columns · 3 rows

About saving. The generated page keeps edits in whichever browser opens it — so two people editing the same file end up with two different tables. When the table has to be shared, put it on a page with one address instead.

An editable HTML table is a table that looks like a designed page and can still be typed into. A table in a document is usually read-only, and a table in a spreadsheet is usually ugly.

An editable HTML table: click a cell and type, click a header to sort. One file, no library.
An editable HTML table: click a cell and type, click a header to sort. One file, no library.

This builder makes the third thing: set the columns and rows, and copy out one self-contained file whose cells edit on click and whose columns sort when their header is clicked.

How to build an editable HTML table

  1. Name the table and set the columns. Type a title in the top box, then rename the headers. Add column and Remove column change the width.
  2. Fill in the rows. Type into the cells. Add row and Remove row change the length. Everything typed here ends up in the file.
  3. Check the result. The Result tab shows the finished table. Click any cell to edit it; click a header to sort by that column. The HTML tab shows the code that produces it.
  4. Copy the HTML. Copy the HTML puts the whole file on the clipboard. Paste it into an .html file, into an existing page, or into a NOS document if more than one person needs the same rows.

The whole trick is one attribute

<td contenteditable="true">In review</td>

That is it. No library, no framework. The browser turns that cell into a text field when you click it. It has worked in every major browser for years, and it is the least-known useful attribute in HTML.

Two things it does not do, which catch people out:

  • It does not save anything by itself. Reload the page and the typing is gone, unless a script stores it, which the generated file does.
  • It does not validate anything. A cell that should hold a date will happily hold "next Tuesday-ish".

Sorting by column

Sorting needs a little script, and the part worth getting right is number handling. Sort text and you get 1, 10, 100, 9. The generated file checks first:

Sorting by column: the header toggles ascending and descending, and numbers sort as numbers.
Sorting by column: the header toggles ascending and descending, and numbers sort as numbers.
<script>
  var x = a.cells[i].textContent.trim();
  var y = b.cells[i].textContent.trim();
  var nx = parseFloat(x.replace(/[^0-9.-]/g, ''));
  var ny = parseFloat(y.replace(/[^0-9.-]/g, ''));
  var numeric = x !== '' && y !== '' && !isNaN(nx) && !isNaN(ny);
  return numeric ? nx - ny : x.localeCompare(y);
</script>

Stripping non-digits before parsing is what makes $1,284 and 41 min sort correctly as numbers rather than as text. And localeCompare rather than < is what makes names with accents land in the right place.

One accessibility detail while you are there: set aria-sort="ascending" on the header you sorted by. Screen readers announce it, and it costs one line.

Keeping edits between reloads

The generated page writes the rows into local storage on every change:

<script>
  function save() {
    var rows = [].map.call(table.tBodies[0].rows, function (r) {
      return [].map.call(r.cells, function (c) { return c.textContent; });
    });
    try { localStorage.setItem(KEY, JSON.stringify(rows)); } catch (e) {}
  }
  table.addEventListener('input', save);
</script>

The try is not decoration. Local storage throws rather than returning an error in two ordinary situations: private browsing modes, and pages rendered inside a restricted frame. Unguarded, that exception stops the rest of the script, so the table becomes unsortable as well as unsaveable. Wrap every storage call.

This is also why the preview above can be typed into but will not remember: the preview runs in a sandboxed frame, which is the restricted case. Copy the file and open it directly and the saving works.

Where a standalone editable table stops working

A screenshot of the page ✗ Text is not selectable ✗ Numbers cannot be copied ✗ Charts stop being interactive ✗ Goes stale the moment data changes The live page ✓ Text selects and copies ✓ Tables can be read by tools ✓ Charts still respond to hover ✓ Update the source, link is current
An image of a table versus a table that can still be read, sorted and copied.
A standalone file forgets edits on reload. At an address, everyone edits the same rows.
A standalone file forgets edits on reload. At an address, everyone edits the same rows.

Local storage is per browser, per machine. That produces a specific and very common failure:

  1. You send the file to four people.
  2. All four type into it.
  3. There are now five versions of the truth, four of which nobody else can see.
  4. Someone asks which is current. There is no answer.

Nothing is wrong with the file. The model is wrong: edits are being stored next to each reader instead of next to the table.

When the table has to be shared

The fix is not a better file; it is one address. If the table lives on a page that everybody opens, then everybody is looking at the same rows, and a change one person makes is a change the others see.

That is the case NOS is built for: paste the table HTML into a document and it renders exactly as written, the cells hold real text you can click and correct, and the share link stays the same as the contents change.

Use the standalone file when you need something that works with no network and belongs to one person. Use a page with an address when more than one person needs the same numbers. Sharing a table covers the switch.

Where an editable table earns its keep

  • A checklist for a launch or an event. Owner, status, due date. People update their own row.
  • A price or spec sheet a client can annotate. They type a question into the cell instead of writing a separate mail.
  • A tracker that lives in a document. Paste the table into a NOS page next to the notes it belongs to, and the notes and the numbers stay together.
  • A quick data entry form. Blank rows, sensible headers, Download CSV at the end.

Getting the design right

A few choices make the difference between a table that reads well and one that does not:

Choice Do this Why
Column headers background + smaller uppercase text The eye needs to find the top row without a border
Number columns text-align: right and font-variant-numeric: tabular-nums Digits line up, so magnitudes are comparable at a glance
Row separation A hairline bottom border, no vertical lines Vertical rules add noise without adding information
Focus state A visible outline on td:focus Otherwise nobody can tell the cell is editable
Long text vertical-align: top Mid-aligned text in a tall row looks like a mistake

The focus state is the one people skip, and it is the one that decides whether anybody discovers the table is editable at all. If clicking a cell produces no visible change, the feature might as well not be there. The generated file includes it.

What the generated file can and cannot do

Standalone file A page at one address
Type into a cell Yes Yes
Sort by column Yes Yes
Survive a reload On that browser only Yes
Two people see the same rows No Yes
Merge two people's edits No Not needed
Works with no network Yes No
Export CSV Yes Yes

The two hard noes are not implementation gaps; they follow from where the edits are stored. See localStorage for the mechanism.

The attribute behind it

One attribute does the editing. contenteditable covers the paste handling and focus style that the generated file already includes, and the reasons a full document editor should not be built this way.

Questions people ask

How do I make an HTML table editable?

Add contenteditable="true" to each cell. The browser turns the cell into a text field when it is clicked. No library is needed. The builder above writes this for you, along with sorting and a visible focus style.

Does the editable table save my changes?

The generated file writes the rows into the browser's local storage on every change, so a reload on the same browser shows your edits. It does not save anywhere else, and another person opening the file starts from the original rows.

Can two people edit the same table?

Not with a standalone file. Each copy stores its edits on its own machine, so four people produce four versions. Put the table on a page at one address, such as a NOS document, and everyone edits the same rows.

Why do numbers sort in the wrong order?

Plain text sorting puts 10 before 9. The generated file strips currency signs and units, tries to read the cell as a number, and sorts numerically when both cells are numbers.

Can I export the table?

Yes. The generated page has a Download CSV button that writes the current rows, including your edits, to a file that opens in any spreadsheet.

Keep reading