CSVtoTable
CSVtoTable converts CSV, TSV, and Excel files into interactive HTML tables.
- Single native binary with embedded frontend assets
- Standalone HTML output that works offline — data, styles, and scripts all inlined
- CSV, TSV, and Excel (
.xlsx) input, gzip archives included - Local files, URLs, standard input, or several files combined into one table
- BOM and UTF-16 detected automatically;
--encoding,--delimiter,--quotecharfor the rest - Search, per-column filters with clearable chips, sorting, pagination, and virtual scrolling
- Copy, CSV, JSON, and print exports, plus column show/hide
- Markdown or raw HTML page title and description, inline or read from a file
- Five colour themes, switchable in the page or fixed with
--theme - Themes are just CSS variables — define your own with
--cssand it joins the picker --cssand--jsinline your own stylesheet and script, with the live table API exposed- Mobile-responsive layout
Try the live demo — a page built by CSVtoTable from the sample data, served as one static file.
Usage
# Write a standalone page
csvtotable input.csv page.html
# Combine files with the same columns
csvtotable input1.csv input2.csv page.html
# Gzip-compressed CSV files
csvtotable data.csv.gz data.html
# Read an Excel workbook
csvtotable sales.xlsx sales.html
# Fetch CSV directly from a URL
csvtotable https://raw.githubusercontent.com/vividvilla/csvtotable/master/demo/meteorite-landings-1.csv meteorites.html
# Open a temporary page in the default browser
csvtotable data.csv --serve
# Add a title and generate headers for headerless data
csvtotable data.csv data.html --title "Sales" --no-header
# Title and description accept Markdown
csvtotable data.csv data.html --title "Sales for **Q3**" --description "Pulled from \`warehouse\`. See the [runbook](https://example.com)."
# or pass a markdown file as decription
csvtotable data.csv data.html --title "Sales for **Q3**" --description @sales.md
# or use raw HTML instead of Markdown
csvtotable data.csv data.html --title-html '<span>Sales <b>Q3</b></span>'
csvtotable data.csv data.html --title-html '<span>Sales <b>Q3</b></span>' --description-html @description.html
# Paginate instead of showing every row
csvtotable data.csv data.html --page-size 50
# Open in a particular theme
csvtotable data.csv data.html --theme solarized
# Add your own CSS and JavaScript
csvtotable data.csv data.html --css brand.css --js setup.js
# Read stdin and write stdout
curl -L https://example.com/data.csv | csvtotable - - > data.html
# Explore all the available options
csvtotable --help
Install
uvx, pipx, or pip
Run without installing:
uvx csvtotable data.csv data.html
Or install it:
pipx install csvtotable
uv tool install csvtotable
pip install csvtotable # inside a virtual environment
npx or npm
npx @vividvilla/csvtotable data.csv data.html # run without installing
npm install --global @vividvilla/csvtotable # or install globally
To run a particular published version:
uvx csvtotable@X.Y.Z data.csv data.html
npx @vividvilla/csvtotable@X.Y.Z data.csv data.html
Homebrew
brew install vividvilla/tap/csvtotable
Standalone binary
Download an archive from GitHub Releases,
verify it with SHA256SUMS, and place csvtotable (csvtotable.exe on Windows)
on your PATH.
Prebuilt binaries support Linux x86-64/ARM64, macOS 12+ x86-64/Apple Silicon, and Windows 10+ x86-64.
Styling
The page is plain semantic HTML, and every element CSVtoTable owns carries a
csvtotable- class. These are the stable hooks:
| Hook | Element |
|---|---|
.csvtotable |
<main>, the page root |
.csvtotable-header |
<header> wrapping the title and description |
.csvtotable-title |
<h1> page heading |
.csvtotable-description |
description block |
.csvtotable-table |
the <table> |
.csvtotable-theme |
theme picker |
.csvtotable-filters |
active-filter chip row |
.csvtotable-chip |
one active filter, with -key, -value, and -remove parts |
.csvtotable-clear |
the "clear all" control |
A theme is nothing but a block of colour variables. Every rule in the stylesheet reads them, so a new theme is a copy of one block with different values — no rules to write and nothing else to touch:
[data-theme="my-theme"] {
color-scheme: dark; /* so scrollbars and dropdowns match */
--ct-paper: #1a1b26; /* page background */
--ct-ink: #c0caf5; /* body text */
--ct-muted: #7f88b0; /* labels, secondary text */
--ct-rule: #232433; /* row separators */
--ct-rule-strong: #343b58;
--ct-accent: #7aa2f7; /* focus, active sort, filter chips */
--ct-wash: #1f2335; /* accent tint behind chips */
--ct-hover: #1e2030; /* row and control hover */
}
Switching themes is just swapping data-theme on <html>. Type and metrics sit
outside the palettes in the --ct-text-* scale and --ct-sans/--ct-mono,
since they do not vary by theme. Headings are styled by level (h1 to h6), so
a Markdown heading in a description matches the same level elsewhere; start
description headings at ## to keep one <h1> per page.
Nothing is styled through an ID, so a stylesheet loaded after the page's own
<style> overrides any of the above with a single class selector. Classes
beginning dt- come from DataTables and may change when it is upgraded.
Custom CSS and JavaScript
--css and --js inline a stylesheet and a script into the page, keeping the
output a single self-contained file. Both take a file path:
csvtotable data.csv data.html --css brand.css --js setup.js
A leading @ is accepted too, for symmetry with --description, but means
nothing here: --css @brand.css and --css brand.css are the same.
Placement is what makes them useful. The stylesheet goes last in <head>, after
the built-in one, so a single class selector overrides anything above without
!important. The script goes last in <body>, after the table is built, and
CsvToTable.table holds the live DataTables API
instance:
CsvToTable.table.order([2, "desc"]).draw(); // sort by the third column
CsvToTable.table.column(0).visible(false); // hide the first column
The table's height is fitted on the next animation frame, so a script that
measures layout should wrap the read in requestAnimationFrame. Column widths
and the scroll height are set as inline styles, which a stylesheet cannot
override — use --height for that.
A whole new palette is a stylesheet plus a matching --theme. The name does not
have to be one of the built-ins as long as --css defines it, and the page's
theme picker will list it alongside them:
csvtotable data.csv data.html --css custom.css --theme tokyonight
Selecting "Auto" in the picker unpins data-theme and falls back to the
built-in light and dark palettes, so put anything that should survive that in
:root or a class rule and keep [data-theme] blocks for the palette itself.
Both flags are trusted input: whatever the files contain runs for anyone who
opens the page, so do not generate them from untrusted data. Content is escaped only
so it cannot break out of its <style> or <script> element; it is not
sanitised.
Run csvtotable --help for all options or csvtotable --version for the version.
For compatibility with version 2, --caption, --display-length, --pagination,
and --export still work; the last two disable those features.
Development
Building requires Go 1.25+ and Bun. Distribution packaging also requires Python
and npm. table/dist is generated before the Go build and embedded in the final
binary.
nix develop # optional development environment
make build # frontend and build/csvtotable
make test # frontend, formatting, vet, and tests
make demo # the published demo page under site/
make dist # binary and host-platform packages under dist/
./build/csvtotable demo/meteorite-landings-1.csv demo/meteorite-landings-2.csv /tmp/meteorites.html
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file csvtotable-3.1.0-py3-none-win_amd64.whl.
File metadata
- Download URL: csvtotable-3.1.0-py3-none-win_amd64.whl
- Upload date:
- Size: 6.0 MB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d31573d57828e1af62684694452bba239ff7304b889ed19f3502278a0bf0d2f6
|
|
| MD5 |
d2bec721a3a1c879d258a8841e018c35
|
|
| BLAKE2b-256 |
57205afa45834c52278dd78c1de0f21443e3079ae806c7433a585d9aa12054cb
|
Provenance
The following attestation bundles were made for csvtotable-3.1.0-py3-none-win_amd64.whl:
Publisher:
release.yml on vividvilla/csvtotable
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
csvtotable-3.1.0-py3-none-win_amd64.whl -
Subject digest:
d31573d57828e1af62684694452bba239ff7304b889ed19f3502278a0bf0d2f6 - Sigstore transparency entry: 2547503656
- Sigstore integration time:
-
Permalink:
vividvilla/csvtotable@ec58271270203b3d545f6d398e261ecb87d62095 -
Branch / Tag:
refs/tags/v3.1.0 - Owner: https://github.com/vividvilla
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ec58271270203b3d545f6d398e261ecb87d62095 -
Trigger Event:
push
-
Statement type:
File details
Details for the file csvtotable-3.1.0-py3-none-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: csvtotable-3.1.0-py3-none-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 5.9 MB
- Tags: Python 3, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0658276ca01b5f4ecdc94043de19acad41dfca64e9ed438c387d88710db7dc5d
|
|
| MD5 |
056ad62e43e2abb79645a5996fb1d49b
|
|
| BLAKE2b-256 |
e17a1f3e68585fe9704e0bf9fa9e9eb31d058bc64a9b277194d1691a5c7f03df
|
Provenance
The following attestation bundles were made for csvtotable-3.1.0-py3-none-musllinux_1_2_x86_64.whl:
Publisher:
release.yml on vividvilla/csvtotable
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
csvtotable-3.1.0-py3-none-musllinux_1_2_x86_64.whl -
Subject digest:
0658276ca01b5f4ecdc94043de19acad41dfca64e9ed438c387d88710db7dc5d - Sigstore transparency entry: 2547503982
- Sigstore integration time:
-
Permalink:
vividvilla/csvtotable@ec58271270203b3d545f6d398e261ecb87d62095 -
Branch / Tag:
refs/tags/v3.1.0 - Owner: https://github.com/vividvilla
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ec58271270203b3d545f6d398e261ecb87d62095 -
Trigger Event:
push
-
Statement type:
File details
Details for the file csvtotable-3.1.0-py3-none-musllinux_1_2_aarch64.whl.
File metadata
- Download URL: csvtotable-3.1.0-py3-none-musllinux_1_2_aarch64.whl
- Upload date:
- Size: 5.4 MB
- Tags: Python 3, musllinux: musl 1.2+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
90dd94b775f7d7c7c298d90f05402f025f5b76e988524aa3295d6d63f5505569
|
|
| MD5 |
947946f603fb7736cdf18202471caa7a
|
|
| BLAKE2b-256 |
bc270e7e30e601697a62295df8929e54117c4375f268eaf47ab71a1179141bd0
|
Provenance
The following attestation bundles were made for csvtotable-3.1.0-py3-none-musllinux_1_2_aarch64.whl:
Publisher:
release.yml on vividvilla/csvtotable
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
csvtotable-3.1.0-py3-none-musllinux_1_2_aarch64.whl -
Subject digest:
90dd94b775f7d7c7c298d90f05402f025f5b76e988524aa3295d6d63f5505569 - Sigstore transparency entry: 2547503566
- Sigstore integration time:
-
Permalink:
vividvilla/csvtotable@ec58271270203b3d545f6d398e261ecb87d62095 -
Branch / Tag:
refs/tags/v3.1.0 - Owner: https://github.com/vividvilla
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ec58271270203b3d545f6d398e261ecb87d62095 -
Trigger Event:
push
-
Statement type:
File details
Details for the file csvtotable-3.1.0-py3-none-manylinux_2_17_x86_64.whl.
File metadata
- Download URL: csvtotable-3.1.0-py3-none-manylinux_2_17_x86_64.whl
- Upload date:
- Size: 5.9 MB
- Tags: Python 3, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1b9188c454f3bd7996c4323b0fa83afc5a1106b03675bad0360db967a6857e0a
|
|
| MD5 |
03c773dc5fff6aca280597c88e0f7d49
|
|
| BLAKE2b-256 |
c794ce82202fcade335b32e2ade4a316594fef0729016e468bf532cdf7842264
|
Provenance
The following attestation bundles were made for csvtotable-3.1.0-py3-none-manylinux_2_17_x86_64.whl:
Publisher:
release.yml on vividvilla/csvtotable
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
csvtotable-3.1.0-py3-none-manylinux_2_17_x86_64.whl -
Subject digest:
1b9188c454f3bd7996c4323b0fa83afc5a1106b03675bad0360db967a6857e0a - Sigstore transparency entry: 2547503816
- Sigstore integration time:
-
Permalink:
vividvilla/csvtotable@ec58271270203b3d545f6d398e261ecb87d62095 -
Branch / Tag:
refs/tags/v3.1.0 - Owner: https://github.com/vividvilla
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ec58271270203b3d545f6d398e261ecb87d62095 -
Trigger Event:
push
-
Statement type:
File details
Details for the file csvtotable-3.1.0-py3-none-manylinux_2_17_aarch64.whl.
File metadata
- Download URL: csvtotable-3.1.0-py3-none-manylinux_2_17_aarch64.whl
- Upload date:
- Size: 5.4 MB
- Tags: Python 3, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
44015e7029d102ca394e1df88be23d43c3365c646536c7eca1af0dcea76ff0dc
|
|
| MD5 |
f67c0f1049f69260b2e6b1583f042bea
|
|
| BLAKE2b-256 |
ad275da91eaab7112c04d77a84ef28fe2583d808c3f3c8bebf1e4c19637e0eb8
|
Provenance
The following attestation bundles were made for csvtotable-3.1.0-py3-none-manylinux_2_17_aarch64.whl:
Publisher:
release.yml on vividvilla/csvtotable
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
csvtotable-3.1.0-py3-none-manylinux_2_17_aarch64.whl -
Subject digest:
44015e7029d102ca394e1df88be23d43c3365c646536c7eca1af0dcea76ff0dc - Sigstore transparency entry: 2547503729
- Sigstore integration time:
-
Permalink:
vividvilla/csvtotable@ec58271270203b3d545f6d398e261ecb87d62095 -
Branch / Tag:
refs/tags/v3.1.0 - Owner: https://github.com/vividvilla
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ec58271270203b3d545f6d398e261ecb87d62095 -
Trigger Event:
push
-
Statement type:
File details
Details for the file csvtotable-3.1.0-py3-none-macosx_12_0_x86_64.whl.
File metadata
- Download URL: csvtotable-3.1.0-py3-none-macosx_12_0_x86_64.whl
- Upload date:
- Size: 6.0 MB
- Tags: Python 3, macOS 12.0+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4ad73e4623e0d9d3cf3bd0d809a54987820327b2bde3770184d6fee991977d43
|
|
| MD5 |
c1743bef31b7c9ecb457c2545edfafd9
|
|
| BLAKE2b-256 |
bac065a78ca738c78d28a018529c1464c06c8f8f73227d0d42ae101e64d49403
|
Provenance
The following attestation bundles were made for csvtotable-3.1.0-py3-none-macosx_12_0_x86_64.whl:
Publisher:
release.yml on vividvilla/csvtotable
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
csvtotable-3.1.0-py3-none-macosx_12_0_x86_64.whl -
Subject digest:
4ad73e4623e0d9d3cf3bd0d809a54987820327b2bde3770184d6fee991977d43 - Sigstore transparency entry: 2547503894
- Sigstore integration time:
-
Permalink:
vividvilla/csvtotable@ec58271270203b3d545f6d398e261ecb87d62095 -
Branch / Tag:
refs/tags/v3.1.0 - Owner: https://github.com/vividvilla
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ec58271270203b3d545f6d398e261ecb87d62095 -
Trigger Event:
push
-
Statement type:
File details
Details for the file csvtotable-3.1.0-py3-none-macosx_12_0_arm64.whl.
File metadata
- Download URL: csvtotable-3.1.0-py3-none-macosx_12_0_arm64.whl
- Upload date:
- Size: 5.6 MB
- Tags: Python 3, macOS 12.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
154a9ec3b6677f772e418a98e6825219f036be7c91c0ef6f000d487a5c5f2c79
|
|
| MD5 |
cd7b2756c8dec866aa90278b405d00f1
|
|
| BLAKE2b-256 |
205ee5b788b951f657dd451b8ca3e3bb2628e2979b0de7b110df2d83adedf81d
|
Provenance
The following attestation bundles were made for csvtotable-3.1.0-py3-none-macosx_12_0_arm64.whl:
Publisher:
release.yml on vividvilla/csvtotable
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
csvtotable-3.1.0-py3-none-macosx_12_0_arm64.whl -
Subject digest:
154a9ec3b6677f772e418a98e6825219f036be7c91c0ef6f000d487a5c5f2c79 - Sigstore transparency entry: 2547504066
- Sigstore integration time:
-
Permalink:
vividvilla/csvtotable@ec58271270203b3d545f6d398e261ecb87d62095 -
Branch / Tag:
refs/tags/v3.1.0 - Owner: https://github.com/vividvilla
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ec58271270203b3d545f6d398e261ecb87d62095 -
Trigger Event:
push
-
Statement type: