# ListViewTable
`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](https://gfazioli.github.io/mantine-list-view-table/) 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:
```aardvark
{% 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:
```aardvark
{% 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:
```aardvark
{% 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](/components/data-display/card/) alongside other
content — here a short [text](/components/typography/text/) lead-in above a files table:
Recent files
```aardvark
{% 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:
```css
/* 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](https://gfazioli.github.io/mantine-list-view-table/) 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:
Source: Markdown
```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'} %}
```
Source: Python
```python
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'})
```