# Data Tables


## Overview

The `data-table` shortcode renders tables from JSON, CSV, or YAML data files.
Data files are resolved from the **page bundle** first, then the global **assets/** directory.
Tables are fully rendered at build time as static HTML.
Setting `interactive="true"` progressively enhances the table with client-side column sorting -- without JavaScript, the table remains fully readable.

---

## Parameters

---

## Data file location

The shortcode looks for data files in two places, in order:

1. **Page bundle** -- files co-located with the page's `index.md`. Use this for page-specific data.
2. **Global assets** -- the project's `assets/` directory (or any directory mounted to it). Use this for shared data.

For page bundles, the path is relative to the bundle directory. For global assets, the path is relative to `assets/` and conventionally starts with a `/` (e.g., `/data/endpoints.json`).

### Page bundle example

```text
content/
└── my-page/
    ├── index.md        <-- 
    └── results.json    <-- resolved from page bundle
```

### Global assets example

```text
assets/
└── data/
    └── endpoints.json  <-- 
```

---

## Data formats

### JSON

An array of objects. Keys become column headers, transformed with `humanize` and `title` by default (e.g., `rate_limit` becomes "Rate Limit"). Columns are sorted **alphabetically** -- use the `columns` parameter to control display order.

```json
[
  { "endpoint": "/api/v1/users", "method": "GET", "status": "stable" },
  { "endpoint": "/api/v1/groups", "method": "POST", "status": "beta" }
]
```

### CSV

Standard CSV with a header row. Headers are used exactly as written -- no transformation is applied. Columns appear in file order. Quoted fields with commas and escaped quotes are handled per RFC 4180.

```text
Endpoint,Method,Status
/api/v1/users,GET,stable
/api/v1/groups,POST,beta
```

### YAML

An array of objects, same structure as JSON. Keys are transformed and sorted the same way.

```yaml
- endpoint: /api/v1/users
  method: GET
  status: stable
- endpoint: /api/v1/groups
  method: POST
  status: beta
```

---

## Examples

### Static table (default)

The simplest usage -- renders all columns from a JSON file as a static table. Columns appear in alphabetical order.

```text

```

### Page bundle resource

Data files co-located with the page's `index.md` are resolved automatically. This `team.yaml` file lives in the same directory as this page.

```text

```

### Selecting columns and controlling order

Use `columns` to choose which columns to display, in the exact order listed. This is especially useful for JSON and YAML sources where the default order is alphabetical.

```text

```

### Hiding columns

Use `hide` to remove specific columns while keeping all others in their default order. If both `columns` and `hide` are set, `columns` is applied first, then `hide` removes from that subset.

```text

```

### Overriding column headers

Use `labels` to override auto-generated headers. The format is `key:Display Label` pairs, comma-separated. Unescaped colons in label values are preserved (e.g., `key:Prefix: Suffix` produces the label "Prefix: Suffix").

```text

```

### Raw keys (humanize disabled)

Set `humanize="false"` to display JSON/YAML keys verbatim instead of applying humanize and title case. This has no effect on CSV sources, which always use headers as-is.

```text

```

### CSV source

CSV headers appear exactly as written in the file.

```text

```

### Narrow variant

Use `variant="narrow"` to constrain the table to two-thirds of the content area.

```text

```

### Borderless theme

Use `theme="borderless"` for a clean, minimal table without borders or row striping.

```text

```

### Static sort

Use `sort` to order rows at build time. This works on static tables without `interactive`.

```text

```

### Sortable table

Add `interactive="true"` to enable clickable column headers. Click a header to sort ascending; click again for descending.

```text

```

### Sortable with a default sort

Combine `sort` with `interactive="true"` to set the initial sort column and direction. The sort indicator will reflect the initial state.

```text

```

### Borderless with sorting

Combine `theme="borderless"` with `interactive="true"` for a minimal sortable table.

```text

```

### Markdown in cells

Set `markdownify="true"` to process cell values as markdown. Bold, italic, links, and inline code all render as formatted text.

```text

```

**Caution:** 
Enabling `markdownify` also causes raw HTML in data values to be rendered as HTML, not escaped. Only use this with trusted data sources.

---

## Special characters

If your column names contain commas or colons, use `\,` and `\:` escape sequences in the `columns`, `hide`, `labels`, and `sort` parameters.

### Selecting columns with special characters

```text

```

### Label overrides with special characters

Escape sequences work in both the key and value portions of `labels`.

```text

```

### Sorting and hiding with special characters

```text

```

```text

```

---

## Warnings and validation

The shortcode produces build-time warnings for common mistakes:

- **Duplicate column headers.** Duplicate keys in the `labels` parameter or duplicate CSV column headers trigger a warning. The first occurrence wins.
- **Invalid sort column.** If the `sort` column does not exist in the data, a warning is emitted and no sort is applied.
- **Invalid sort direction.** If the sort direction is not `asc` or `desc`, a warning is emitted and the default (`asc`) is used.

---

## Limitations

- **Plain text by default.** Cell values are rendered as escaped plain text. Markdown syntax, HTML tags, and shortcode invocations appear as literal strings. Set `markdownify="true"` to opt in to markdown processing.
- **No per-column markdownify.** The `markdownify` flag applies to all cells. There is no way to enable it for individual columns.
- **Column ordering.** JSON and YAML columns are sorted alphabetically. Use `columns` to set a specific order. CSV columns always follow file order.
- **Missing values.** If a JSON or YAML row is missing a key that other rows define, the cell renders as empty.

