ListViewTable
The built-in listviewtable tag — a Finder-style list-view table with sortable columns and optional drag-to-reorder and resize. A Community Component wrapping @gfazioli/mantine-list-view-table.
listviewtable renders a Finder-style list-view table — rows of records under sortable
column headers, with optional drag-to-reorder and drag-to-resize columns. It hydrates
into a fully interactive island in the browser, with no JavaScript to write.
You pass two JSON strings: data, an array of row record objects, and columns, an array
of {key, title, sortable, width, textAlign, sticky} column definitions. The tag parses both
at build time and hands them to the table. Use it as
{% listviewtable %} in Markdown, or call it from Python logic (loops,
snippets) via component('aardvark', 'listviewtable', …).
A Community Component — wraps
ListViewTable by gfazioli, MIT
licensed, npm @gfazioli/mantine-list-view-table.
Demonstrations
Basic list view
A data array of records and a columns array of definitions. Each column’s key selects the
field to display; title labels the header and sortable lets the reader sort by it:
{% listviewtable data='[{"name":"Documents","kind":"Folder","size":"--"},{"name":"README.md","kind":"Markdown","size":"2.1 KB"},{"name":"package.json","kind":"JSON","size":"1.8 KB"},{"name":"src","kind":"Folder","size":"--"}]' columns='[{"key":"name","title":"Name","sortable":true},{"key":"kind","title":"Kind","sortable":true,"width":140},{"key":"size","title":"Size","sortable":true,"width":120,"textAlign":"right"}]' %}
Borders, striping, and hover highlight
Turn on withTableBorder, withColumnBorders, striped, and highlightOnHover for a more
table-like, scannable look:
{% listviewtable data='[{"name":"Ada Lovelace","role":"Admin","status":"Active"},{"name":"Alan Turing","role":"Editor","status":"Active"},{"name":"Grace Hopper","role":"Viewer","status":"Invited"}]' columns='[{"key":"name","title":"Name","sortable":true},{"key":"role","title":"Role","sortable":true,"width":140},{"key":"status","title":"Status","width":140}]' withTableBorder=true withColumnBorders=true striped=true highlightOnHover=true %}
Reorderable and resizable columns
enableColumnReordering lets readers drag column headers to reorder them;
enableColumnResizing lets them drag the column edges to resize. Set a height to cap the
table and scroll the body:
{% listviewtable data='[{"id":1,"task":"Write docs","owner":"Ada","due":"2024-06-01"},{"id":2,"task":"Ship release","owner":"Alan","due":"2024-06-04"},{"id":3,"task":"Review PRs","owner":"Grace","due":"2024-06-02"}]' columns='[{"key":"task","title":"Task","sortable":true},{"key":"owner","title":"Owner","sortable":true,"width":140},{"key":"due","title":"Due","sortable":true,"width":140,"textAlign":"right"}]' enableColumnReordering=true enableColumnResizing=true withTableBorder=true %}
With other components
A list view sits naturally inside a card alongside other content — here a short text lead-in above a files table:
Recent files
{% card %}
{% text size='sm' c='dimmed' %}Recent files{% endText %}
{% listviewtable data='[{"name":"report.pdf","size":"482 KB"},{"name":"notes.txt","size":"3 KB"}]' columns='[{"key":"name","title":"Name","sortable":true},{"key":"size","title":"Size","width":120,"textAlign":"right"}]' withTableBorder=true highlightOnHover=true %}
{% endCard %}
Attributes
Every attribute is optional except that a useful table needs both data and columns; omit
any other to take its upstream default. The body is ignored — listviewtable is a viewer, not
a container.
| Attribute | Valid values | Description |
|---|---|---|
data |
JSON array string | The rows — an array of record objects. Parsed at build time; a malformed value warns and degrades to an empty array. |
columns |
JSON array string | The columns — an array of {key, title, sortable, width, minWidth, maxWidth, textAlign, sticky, noWrap, ellipsis, hidden} objects. key selects the record field; title labels the header. |
height |
CSS length (string) | Cap the table height; the body scrolls past it. |
rowKey |
String | Record field to use as the unique row key. |
borderRadius |
xs, sm, md, lg, xl |
Outer container radius when withTableBorder is on (default sm). |
striped |
true / false (default false) |
Stripe alternate rows. |
withTableBorder |
true / false (default false) |
Draw a border around the table. |
withColumnBorders |
true / false (default false) |
Draw borders between columns. |
withRowBorders |
true / false (default true) |
Draw borders between rows. |
highlightOnHover |
true / false (default false) |
Highlight a row on hover. |
stickyHeader |
true / false (default false) |
Keep the header row sticky while the body scrolls. |
tabularNums |
true / false (default false) |
Use tabular (fixed-width) numerals. |
enableColumnReordering |
true / false (default false) |
Let readers drag column headers to reorder. |
enableColumnResizing |
true / false (default false) |
Let readers drag column edges to resize. |
attr={…} |
An object of HTML attributes | Forwards raw HTML attributes onto the rendered element. |
Per-column custom cell renderers (renderCell / renderHeader) are React functions, so they
can’t ride this JSON channel; columns here are plain field projections that display the record’s
value for each column key.
CSS Selector
The table is an island wrapper carrying data-aardvark-island="ListViewTable"; the upstream
component owns the inner table chrome. Style or target it from your own CSS through the island
attribute or any attr-supplied id/class:
/* The ListViewTable island wrapper */
[data-aardvark-island="ListViewTable"] {
margin-block: var(--mantine-spacing-md);
}
The upstream package also exposes CSS variables (e.g. --lvt-border-color,
--lvt-shadow-color, --list-view-cell-font-size) and Styles API selectors for the header,
rows, cells, and sticky columns — see the
upstream documentation for the full list.
Injecting Attributes
Pass attr={…} to forward raw HTML attributes (an id, class, data-*, ARIA attributes,
inline event handlers) straight onto the rendered element — exactly like
component('aardvark', 'listviewtable', attr={…}). These ride the data-aardvark-attr
channel, not React props, so they don’t collide with the component’s own props:
{% listviewtable data='[{"name":"file.txt","size":"1 KB"}]' columns='[{"key":"name","title":"Name"},{"key":"size","title":"Size"}]' attr={'id': 'demo-table', 'data-role': 'file-list'} %}
component('aardvark', 'listviewtable',
data='[{"name":"file.txt","size":"1 KB"}]',
columns='[{"key":"name","title":"Name"},{"key":"size","title":"Size"}]',
attr={'id': 'demo-table', 'data-role': 'file-list'})