The HTML table generator that runs the table
Every other HTML table generator hands you a string and walks away. mk0r generates a live React + Tailwind table on a Vite dev server inside a sandbox, then uses Playwright to click the column headers in a real browser and verify sort works before you see the code.
Build a table nowWhat the top SERP for "html table generator" gives you
I searched the keyword and opened the first five results. Every one of them follows the same pattern: a form asking for row count, column count, border style, cell padding. You click generate, and it prints a blob of HTML and CSS at the bottom of the page with a copy button. Some let you toggle between div based and table based markup. One or two let you pick a color scheme. None of them do any of this:
The gap between "a string of HTML" and "a table that actually works in your product" is everything you are going to do by hand after you paste the string. mk0r closes that gap inside the sandbox, not in your editor.
The pipeline under the hood
When you land on mk0r.com and describe a table, a single prompt fans out to a Vite + React + Tailwind project, a browser that can drive itself, and a git repo that captures the diff. Here is the shape of it.
What your prompt touches
The three destinations are not ideas. They are processes. Vite serves HMR from /app. Playwright MCP is registered for the agent in buildMcpServersConfig in src/core/e2b.ts around line 153. Git commits come from commitTurn after every chat turn that touches files.
The anchor fact: where Playwright lives in the VM
This is the part no competitor can copy, because it is wired into the sandbox template, not the prompt. When the agent is ready to click your freshly generated table, it calls a tool registered like this:
CDP on 127.0.0.1:9222, Chromium binary at /usr/bin/chromium, both preinstalled in the E2B template. That is why Playwright driving the browser is free for every session: the browser is not downloaded on demand, it is already there. The agent navigates to http://localhost:5173 (the Vite dev server), finds the table it just generated, clicks the column header, and reads the DOM back to confirm the rows changed order. If they did not, the next agent turn fixes the broken sort comparator before the turn ends.
What the agent runs while you wait
You see the streamed chat in the UI, but in the VM there is a small terminal session happening for every turn. Below is a faithful trace of what the agent does after it writes UsersTable.tsx and wants to confirm sort works.
The file the agent actually writes
Not pseudo-code, not "here is roughly what the component looks like." This is the kind of output a prompt like "table of users with sortable columns and a filter input" produces, committed to /app/src/components/ inside the VM.
You can export the rendered HTML from the browser if you want a flat string. But the thing committed to the repo is a real component your follow-up prompts can keep evolving.
Static HTML generators vs. mk0r
| Feature | Static HTML table generator | mk0r |
|---|---|---|
| Output | HTML + CSS string | Live React component on a running Vite server |
| Interactive behaviour | None (static markup only) | Sort, filter, row-click tested by Playwright in Chromium |
| Verification | You paste it and hope | Agent navigates to localhost:5173 and reads the DOM back |
| Versioning | None | Every prompt becomes a real git commit |
| Signup required | Often yes (to save tables) | No account, no email |
| Iteration loop | Copy, paste, edit by hand, repeat | Describe the change, agent rebuilds and re-tests |
| Responsive checks | Manual in your own browser | Viewport emulation inside the sandbox |
What you can ask the table to do
Because the output is a live React component, not a dead string, anything you can describe to the agent lands in the file. Here is the typical surface area once the first table is on the screen.
Sortable columns, verified
The agent clicks every column header in the sandboxed Chromium and reads the row order back. If sort does not work, that turn does not finish.
Filter inputs that actually filter
Type-ahead filters get exercised by Playwright typing into the input and checking the DOM row count before and after.
Row actions
Edit, delete, view: each one ends up as a button with a handler, wired into local state or an endpoint you point the agent at.
Responsive without guesswork
Viewport emulation inside the VM means the agent tests 375 px, 768 px, and 1280 px before it declares the table done.
Accessible by default
Headers use <th scope>, sort state uses aria-sort, and keyboard focus order gets checked by the agent when you ask.
Exportable
Ask for a print stylesheet, a CSV export button, or a 'copy visible rows' action; all of them land as real code.
The numbers that matter for a table
For tables, "fast" is the interaction you did not notice. These are the ceilings the sandbox template and its preinstalled Chromium give you out of the box.
Frame count of the hero concept clip rendered above. Remotion generates it on the fly, same engine the agent can use to animate your table cells.
Typical starter dataset scaffolded by the agent. Swap for a fetch to your API in one follow-up prompt.
Per chat turn that changes files. Undo is a git checkout, not a retype.
How to build a working table in five prompts
Describe the columns and intent
'Build a users table with columns name, email, role, last active. Seed it with 20 plausible rows.' The agent writes UsersTable.tsx and imports it into App.tsx.
Ask for sort and see it verified
'Make every column header sortable and show an arrow for the active column.' The agent adds the handler, Playwright clicks every header, and commits only once the DOM reflects the new order.
Add a filter input
'Add a filter input at the top that matches on name and email, case insensitive.' Playwright types a query and checks the row count shrinks as expected.
Wire it to your data
'Load rows from GET /api/users on mount, with a loading state.' The agent adds useEffect + fetch + error boundary, verifies the network tab, and handles the empty case.
Polish, responsive, ship
'Stack rows as cards below 640px and make the whole thing zebra striped.' Playwright emulates the mobile viewport, visually checks the stacked layout, and commits the final version.
When you still want a dead HTML string
Plenty of people search "html table generator" because they want a one-off block to paste into a CMS, a MailChimp template, or an old Wordpress editor. That is a legitimate use case, and mk0r handles it by degrading gracefully. Ask for:
You get exactly that: a portable string you can paste. You lose the Playwright verification and the per-turn commit, because there is nothing to run. That is the trade. The key thing: you get to choose which output shape fits the job, and you do not have to leave the chat to switch modes.
Frequently asked questions
Frequently asked questions
What does mk0r actually output when I ask for an HTML table?
A React component file at /app/src/ inside the sandbox, styled with Tailwind v4, rendered by Vite on port 5173. You see the rendered table live in a screencast while you type follow-up prompts. If you want raw HTML instead, ask for it: the agent can scaffold a standalone HTML + inline CSS version when that is what you need.
How does mk0r 'test' the generated table in a real browser?
The VM ships with Playwright MCP preconfigured. The wiring lives in buildMcpServersConfig in src/core/e2b.ts around line 153: `npx @playwright/mcp --cdp-endpoint http://127.0.0.1:9222` with env PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/chromium. The agent calls it to navigate to the Vite dev server, click column headers, type into filter inputs, and read back the DOM to confirm the sort order changed. Failures loop back into the agent, not you.
Can I get a plain HTML string I can paste into an existing site?
Yes. Ask for a single self-contained HTML file with inline styles. The agent generates one page, you copy it, done. You trade the Playwright verification and live preview for portability. For bigger tables with sort, pagination, and row actions, keep it in the React project and export when ready.
Is every iteration of the table versioned?
Yes. Every chat turn that produces file changes is a real git commit on a real repo inside the VM. 'Add a sortable Price column' is a commit. 'Make the rows striped' is a commit. 'Undo the striping' is a commit. The history lives in a Freestyle-hosted remote the session persists to, so you can diff and revert across turns.
Do I need to sign up, install anything, or pick a template?
No. Go to mk0r.com, type 'table of 20 users with columns name, email, role, and last active, sortable', and the VM, the git repo, the Vite server, and Playwright MCP all spin up for you. No account, no CLI, no plan picker.
How is this different from Jotform tables, tablesgenerator.com, or divtable.com?
Those tools output a markup string. Type your columns, click 'generate', paste into your site. There is no runtime and no testing. mk0r starts with a running app: the table is a React component, it renders in a browser inside the sandbox, and an agent with Playwright MCP proves that the column you marked as sortable actually sorts. The output is a working screen, not a string.
What if my table needs to fetch data from an API?
The generator scaffolds a fetch hook or mock data, renders the table, then lets you iterate. Ask for 'load from /api/users on mount' and the agent wires useEffect + fetch + error state and verifies the network tab in the sandboxed Chromium. If you have an endpoint, paste the schema into the chat; the columns get inferred from it.
Can the table be responsive without breaking on mobile?
Yes, and the agent checks it. Playwright MCP can emulate viewport sizes inside the sandboxed Chromium. Ask for a responsive layout and the agent typically switches to a stacked card layout below 640px, then re-checks the rendered output at both widths before declaring the turn done.
What about a huge dataset, does it stay fast?
For thousands of rows, ask for virtualized rendering. The agent can scaffold react-virtuoso or TanStack Virtual, verify scroll behavior in the sandbox, and confirm the DOM node count stays bounded. You get a performance profile you can trust because it ran in a browser, not in the agent's imagination.
The best way to understand this is to build one
Describe the columns. Ask for sort. Ask for a filter. Watch the agent verify it in Chromium. Every step is a git commit you can walk back.
Start building on mk0r