# Content table editor

> An editable table for structured content with typed columns, cell editing by keyboard, sorting, search, undo and redo, footer totals, validation, CSV export and a save state.

Source: https://docs.nasaqui.com/components/content-table-editor

## Install

```bash
npx shadcn@latest add https://docs.nasaqui.com/r/content-table-editor.json
```

A spreadsheet-like grid for content people maintain by hand: a price list, a glossary, a schedule. Columns have
types (text, number, select, date, checkbox, link, tags), cells edit in place, and the whole thing works from the keyboard.

## When to use

- A table people fill in and correct: many short rows with the same fields.
- You need sorting, search, totals and CSV without building a form per row.

## When not to use

- Read-only tables of records: use `DataTable`.
- Long rich text per row: use `RichTextEditor` in a form.
- A few repeated form groups: use `Repeater`.

## Import

```tsx
import { ContentTableEditor } from "@fadymondy/nasaq/web";
```

## Quick start

```tsx
<ContentTableEditor
  defaultValue={{
    columns: [
      { id: "name", label: "Name", type: "text", required: true },
      { id: "price", label: "Price", type: "number" },
    ],
    rows: [{ id: "r1", cells: { name: "Coffee", price: 12 } }],
  }}
  onSave={async (value) => {
    await api.save(value);
  }}
/>
```

## API

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value`, `defaultValue`, `onValueChange` | `ContentTableValue` | empty | Columns and rows. Controlled or not. |
| `onSave` | `(value) => Promise<void \| { error?: string }>` | none | Adds a Save button and the saved, unsaved and failed states. |
| `onExport` | `(csv) => void` | download | Receives the CSV text. Without it the browser downloads `content-table.csv`. |
| `readOnly` | `boolean` | `false` | Show cells but refuse edits. |
| `editableColumns` | `boolean` | `true` | Add, rename, retype, reorder and delete columns. |
| `searchable` | `boolean` | `true` | The search box. |
| `label`, `toolbar`, `maxHeight`, `className` | | | Grid name, extra toolbar content, scroll height. |
| `labels` | `ContentTableLabels` | localised | English and Arabic built in; overrides any string. |

## Behaviour

- Arrow keys move between cells, Enter or F2 or typing starts editing, Enter or Tab commits, Escape cancels, Delete clears a cell.
- Ctrl or Cmd plus Z and Y undo and redo (50 steps). Deleting rows is undone the same way, so there are no confirm dialogs.
- Header menus sort (empty cells always last), edit, move and delete columns. Row menus insert, duplicate, move and delete.
- Required and link columns show an error on the cell and a count in the toolbar.
- Numbers accept Arabic digits and separators.

## Shared editors

The text and option-list cell editors live in `data-table/cell-editors.tsx` and are shared with DataTable's in-cell edit. This component's props and behaviour are unchanged.

## Accessibility

The grid has `role="grid"` with a roving tab stop, `aria-sort` on sorted headers, and a polite live region for changes. Errors are text plus an icon, not colour alone.

## RTL

Arrow keys mirror, sticky columns and menus use logical sides, and numbers, dates and links stay left to right inside their cells.

## Code

### React

```tsx
<ContentTableEditor
  defaultValue={{
    columns: [
      { id: "name", label: "Name", type: "text", required: true },
      { id: "price", label: "Price", type: "number" },
    ],
    rows: [{ id: "r1", cells: { name: "Coffee", price: 12 } }],
  }}
  onSave={async (value) => {
    await api.save(value);
  }}
/>
```

### shadcn

```tsx
<ContentTableEditor
  defaultValue={{
    columns: [
      { id: "name", label: "Name", type: "text", required: true },
      { id: "price", label: "Price", type: "number" },
    ],
    rows: [{ id: "r1", cells: { name: "Coffee", price: 12 } }],
  }}
  onSave={async (value) => {
    await api.save(value);
  }}
/>
```

### Vue

```vue
<script setup lang="ts">
import { NqContentTableEditor, type ContentTableValue } from "@fadymondy/nasaq/vue";
import { ref } from "vue";

const value = ref<ContentTableValue>({
  columns: [
    { id: "name", label: "Name", type: "text", required: true },
    { id: "price", label: "Price", type: "number" },
    { id: "status", label: "Status", type: "select", options: [{ value: "live", label: "Live", hue: "green" }, { value: "draft", label: "Draft", hue: "amber" }] },
    { id: "active", label: "Active", type: "checkbox", width: 120 },
  ],
  rows: [
    { id: "r1", cells: { name: "Coffee", price: 12, status: "live", active: true } },
    { id: "r2", cells: { name: "Tea", price: 8, status: "draft", active: false } },
  ],
});
async function save(next: ContentTableValue) {
  await new Promise((done) => setTimeout(done, 400));
  console.log("saved", next.rows.length);
}
</script>

<template>
  <NqContentTableEditor v-model="value" :on-save="save" class="w-[44rem]" />
</template>
```

### Blade

```blade
@php
    $value = [
        'columns' => [
            ['id' => 'name', 'label' => 'Name', 'type' => 'text', 'required' => true],
            ['id' => 'price', 'label' => 'Price', 'type' => 'number'],
            ['id' => 'status', 'label' => 'Status', 'type' => 'select', 'options' => [['value' => 'live', 'label' => 'Live', 'hue' => 'green'], ['value' => 'draft', 'label' => 'Draft', 'hue' => 'amber']]],
            ['id' => 'active', 'label' => 'Active', 'type' => 'checkbox', 'width' => 120],
        ],
        'rows' => [
            ['id' => 'r1', 'cells' => ['name' => 'Coffee', 'price' => 12, 'status' => 'live', 'active' => true]],
            ['id' => 'r2', 'cells' => ['name' => 'Tea', 'price' => 8, 'status' => 'draft', 'active' => false]],
        ],
    ];
@endphp
<div x-on:nq-content-save="setTimeout(() => $event.detail.done(), 400)">
    <x-nq::content-table-editor :value="$value" has-save class="w-[44rem]" />
</div>
```

### HTML + Alpine

```html
<div x-on:nq-content-save="setTimeout(() => $event.detail.done(), 400)">
    <div data-slot="content-table-editor" x-data="nqContentTable(JSON.parse('{\u0022value\u0022:{\u0022columns\u0022:[{\u0022id\u0022:\u0022name\u0022,\u0022label\u0022:\u0022Name\u0022,\u0022type\u0022:\u0022text\u0022,\u0022required\u0022:true},{\u0022id\u0022:\u0022price\u0022,\u0022label\u0022:\u0022Price\u0022,\u0022type\u0022:\u0022number\u0022},{\u0022id\u0022:\u0022status\u0022,\u0022label\u0022:\u0022Status\u0022,\u0022type\u0022:\u0022select\u0022,\u0022options\u0022:[{\u0022value\u0022:\u0022live\u0022,\u0022label\u0022:\u0022Live\u0022,\u0022hue\u0022:\u0022green\u0022},{\u0022value\u0022:\u0022draft\u0022,\u0022label\u0022:\u0022Draft\u0022,\u0022hue\u0022:\u0022amber\u0022}]},{\u0022id\u0022:\u0022active\u0022,\u0022label\u0022:\u0022Active\u0022,\u0022type\u0022:\u0022checkbox\u0022,\u0022width\u0022:120}],\u0022rows\u0022:[{\u0022id\u0022:\u0022r1\u0022,\u0022cells\u0022:{\u0022name\u0022:\u0022Coffee\u0022,\u0022price\u0022:12,\u0022status\u0022:\u0022live\u0022,\u0022active\u0022:true}},{\u0022id\u0022:\u0022r2\u0022,\u0022cells\u0022:{\u0022name\u0022:\u0022Tea\u0022,\u0022price\u0022:8,\u0022status\u0022:\u0022draft\u0022,\u0022active\u0022:false}}]},\u0022hasSave\u0022:true}'))" x-modelable="value" x-id="['nq-ct']" x-on:keydown="onGridKey($event)"
    class="flex min-w-0 flex-col gap-3 w-[44rem]">
    <div role="toolbar" x-bind:aria-label="gridLabel()" class="flex flex-wrap items-center gap-2">
        <template x-if="searchable">
            <div class="relative min-w-40 flex-1 sm:max-w-xs">
                <svg aria-hidden="true" class="pointer-events-none absolute start-2.5 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="m21 21-4.34-4.34"/>
  <circle cx="11" cy="11" r="8"/>
</svg>                <input data-slot="input" type="text"
                    x-model="query" x-bind:aria-label="s(`search`)" x-bind:placeholder="s(`searchPlaceholder`)" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control ps-8 pe-8">
                <button type="button" x-show="query" x-on:click="query = ``" x-bind:aria-label="s(`clearSearch`)" style="display: none"
                    class="absolute end-1.5 top-1/2 flex size-6 -translate-y-1/2 items-center justify-center rounded-[4px] text-muted-foreground outline-none hover:text-foreground focus-visible:outline-2 focus-visible:outline-nq-focus"><svg aria-hidden="true" class="size-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M18 6 6 18"/>
  <path d="m6 6 12 12"/>
</svg></button>
            </div>
        </template>
        <div class="ms-auto flex flex-wrap items-center gap-2">
            <template x-if="selectedCount > 0">
                <div class="flex items-center gap-2">
                    <span class="text-body-sm text-muted-foreground" x-text="s(`selected`, n(selected.length))"></span>
                    <button data-slot="button"
     type="button"                         x-on:click="deleteSelected()" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-destructive text-destructive-foreground hover:bg-[color-mix(in_oklab,var(--nq-danger-solid)_88%,var(--nq-fg))] h-control-sm px-2.5">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M10 11v6"/>
  <path d="M14 11v6"/>
  <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/>
  <path d="M3 6h18"/>
  <path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
</svg><span x-text="s(`deleteSelected`, n(selected.length))"></span></button>
                </div>
            </template>
                        <template x-if="editable">
                <div class="flex items-center gap-2">
                    <button data-slot="button"
     type="button"                         x-on:click="undo()" x-bind:aria-label="s(`undo`)" x-bind:title="s(`undo`)" x-bind:disabled="noUndo" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 text-foreground hover:bg-nq-hover size-control-sm p-0">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M9 14 4 9l5-5"/>
  <path d="M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11"/>
</svg></button>
                    <button data-slot="button"
     type="button"                         x-on:click="redo()" x-bind:aria-label="s(`redo`)" x-bind:title="s(`redo`)" x-bind:disabled="noRedo" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 text-foreground hover:bg-nq-hover size-control-sm p-0">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="m15 14 5-5-5-5"/>
  <path d="M20 9H9.5A5.5 5.5 0 0 0 4 14.5A5.5 5.5 0 0 0 9.5 20H13"/>
</svg></button>
                </div>
            </template>
            <button data-slot="button"
     type="button"                         x-on:click="exportCsv()" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 border-border bg-card text-foreground hover:bg-nq-hover h-control-sm px-2.5">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M12 15V3"/>
  <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
  <path d="m7 10 5 5 5-5"/>
</svg><span x-text="s(`exportCsv`)"></span></button>
            <template x-if="canEditColumns">
                <button data-slot="button"
     type="button"                         x-on:click="openNewColumn()" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 border-border bg-card text-foreground hover:bg-nq-hover h-control-sm px-2.5">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <rect width="18" height="18" x="3" y="3" rx="2"/>
  <path d="M9 3v18"/>
  <path d="M15 3v18"/>
</svg><span x-text="s(`addColumn`)"></span></button>
            </template>
            <template x-if="editable && hasSave">
                <button data-slot="button"
     type="button"                         x-on:click="addRow()" x-bind:disabled="noColumns" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 border-border bg-card text-foreground hover:bg-nq-hover h-control-sm px-2.5">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M5 12h14"/>
  <path d="M12 5v14"/>
</svg><span x-text="s(`addRow`)"></span></button>
            </template>
            <template x-if="editable && ! hasSave">
                <button data-slot="button"
     type="button"                         x-on:click="addRow()" x-bind:disabled="noColumns" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-[color-mix(in_oklab,var(--nq-action)_88%,var(--nq-fg))] h-control-sm px-2.5">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M5 12h14"/>
  <path d="M12 5v14"/>
</svg><span x-text="s(`addRow`)"></span></button>
            </template>
            <template x-if="hasSave">
                <span class="inline-flex">
                    <span data-slot="badge" x-show="saveBadge === `saving`" style="display: none" x-text="s(`saving`)" class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border px-1.5 text-caption font-medium border-nq-info/40 bg-nq-info-soft text-nq-info-text"></span>
                    <span data-slot="badge" role="alert" x-show="saveBadge === `error`" style="display: none" x-text="saveMessage || s(`saveFailed`)" class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border px-1.5 text-caption font-medium border-nq-danger/40 bg-nq-danger-soft text-nq-danger-text"></span>
                    <span data-slot="badge" x-show="saveBadge === `unsaved`" style="display: none" x-text="s(`unsaved`)" class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border px-1.5 text-caption font-medium border-nq-warning/40 bg-nq-warning-soft text-nq-warning-text"></span>
                    <span data-slot="badge" x-show="saveBadge === `saved`" x-text="s(`saved`)" class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border px-1.5 text-caption font-medium border-nq-success/40 bg-nq-success-soft text-nq-success-text"></span>
                </span>
            </template>
            <span data-slot="badge" x-show="issueCount > 0" style="display: none" x-text="s(`issues`, n(issueCount))" class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border px-1.5 text-caption font-medium border-nq-danger/40 bg-nq-danger-soft text-nq-danger-text"></span>
            <template x-if="hasSave && editable">
                <button data-slot="button"
     type="button"                         x-on:click="save()" x-bind:disabled="saveOff" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-[color-mix(in_oklab,var(--nq-action)_88%,var(--nq-fg))] h-control-sm px-2.5">
        <span x-text="s(`save`)"></span></button>
            </template>
        </div>
    </div>
    <div class="min-w-0 overflow-auto rounded-card border border-border bg-card" >
        <template x-if="showEmpty">
            <div data-slot="empty-state" class="flex flex-col items-center justify-center gap-3 px-6 py-12 text-center">
                <span data-slot="state-icon" class="inline-flex size-10 items-center justify-center rounded-control border border-border bg-card text-muted-foreground [&_svg]:size-5"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <rect width="18" height="18" x="3" y="3" rx="2"/>
  <path d="M21 9H3"/>
  <path d="M21 15H3"/>
</svg></span>
                <div class="flex max-w-sm flex-col gap-1">
                    <p class="text-label text-foreground" x-text="s(`empty`)"></p>
                    <p class="text-body-sm text-muted-foreground" x-text="s(`emptyHint`)"></p>
                </div>
                <template x-if="canAddFirst">
                    <button data-slot="button"
     type="button"                         x-on:click="addRow()" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-[color-mix(in_oklab,var(--nq-action)_88%,var(--nq-fg))] h-control px-[var(--nq-control-pad)]">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M5 12h14"/>
  <path d="M12 5v14"/>
</svg><span x-text="s(`addRow`)"></span></button>
                </template>
            </div>
        </template>
        <div x-show="! showEmpty" role="grid" data-slot="content-table-grid" x-bind:aria-label="gridLabel()" x-bind:aria-rowcount="view.length + 1" x-bind:aria-describedby="$id(`nq-ct`, `hint`)" class="table w-max min-w-full border-collapse text-body-sm">
            <div role="rowgroup" class="table-header-group sticky top-0 z-10 bg-secondary">
                <div role="row" class="table-row border-b border-border">
                    <div role="columnheader" class="table-cell w-10 px-3 text-start align-middle">
                        <template x-if="editable"><button type="button" role="checkbox" data-slot="checkbox"
    x-bind="boxBind(`all`)" x-bind:aria-label="s(`selectAll`)" class="relative inline-flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-nq-line-strong bg-card text-primary-foreground outline-none transition-colors duration-150 ease-nq data-checked:border-primary data-checked:bg-primary data-indeterminate:border-primary data-indeterminate:bg-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus data-disabled:cursor-not-allowed data-disabled:opacity-50 after:absolute after:-inset-1">
    <span data-slot="checkbox-indicator" class="flex items-center justify-center [&_svg]:size-3 [&_svg]:stroke-3">
        <svg aria-hidden="true" class="hidden [[data-indeterminate]_&]:block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M5 12h14"/>
</svg>        <svg aria-hidden="true" class="hidden [[data-checked]_&]:block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M20 6 9 17l-5-5"/>
</svg>    </span>
</button>
</template>
                    </div>
                    <template x-for="(column, ci) in columns" :key="column.id">
                        <div role="columnheader" x-bind:aria-sort="sortState(column)" x-bind:style="widthStyle(column)" class="table-cell h-row border-s border-border px-1 text-start align-middle text-caption font-medium text-muted-foreground first:border-s-0">
                            <div class="flex items-center gap-1">
                                <button type="button" x-on:click="cycleSort(column)" class="flex min-w-0 flex-1 items-center gap-1.5 rounded-[4px] px-2 py-1 text-start outline-none hover:bg-nq-hover focus-visible:outline-2 focus-visible:outline-nq-focus">
                                    <span class="min-w-0 truncate" x-text="column.label"></span>
                                    <span x-show="column.required" aria-hidden="true" class="text-nq-danger-text" style="display: none">*</span>
                                    <span x-show="isSorted(column)" style="display: none" class="shrink-0 text-foreground [&_svg]:size-3.5">
                                        <svg aria-hidden="true" x-show="sortAscending()" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="m5 12 7-7 7 7"/>
  <path d="M12 19V5"/>
</svg>                                        <svg aria-hidden="true" x-show="! sortAscending()" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M12 5v14"/>
  <path d="m19 12-7 7-7-7"/>
</svg>                                    </span>
                                </button>
                                <div data-slot="dropdown-menu" x-data="nqDropdownMenu(false)" x-modelable="open" class="contents"><button data-slot="dropdown-menu-trigger"
     type="button"                         x-bind="trigger" x-ref="trigger" x-bind:aria-label="s(`columnMenu`, column.label)" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 text-foreground hover:bg-nq-hover size-control-sm p-0">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="1"/>
  <circle cx="19" cy="12" r="1"/>
  <circle cx="5" cy="12" r="1"/>
</svg></button>
                                    <template x-teleport="body">
    <div data-slot="dropdown-menu-content" x-bind="popup" x-init="popupEl = $el" x-nq-presence="open" x-anchor.bottom-end.offset.4="$refs.trigger"
        class="z-50 overflow-hidden rounded-floating border border-border bg-popover p-1.5 text-popover-foreground shadow-floating outline-none max-h-[var(--available-height)] overflow-y-auto transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0 min-w-48"><div data-slot="dropdown-menu-group" role="group" ><div data-slot="dropdown-menu-item" role="menuitem" data-variant="default" x-bind="item"
        x-on:click="sortBy(column, `asc`)" class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control px-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 [&_svg]:text-muted-foreground"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="m5 12 7-7 7 7"/>
  <path d="M12 19V5"/>
</svg><span x-text="s(`sortAsc`)"></span></div>
                                            <div data-slot="dropdown-menu-item" role="menuitem" data-variant="default" x-bind="item"
        x-on:click="sortBy(column, `desc`)" class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control px-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 [&_svg]:text-muted-foreground"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M12 5v14"/>
  <path d="m19 12-7 7-7-7"/>
</svg><span x-text="s(`sortDesc`)"></span></div>
                                            <div data-slot="dropdown-menu-item" role="menuitem" data-variant="default" x-bind="item"
        x-show="isSorted(column)" x-on:click="sortBy(column, null)" class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control px-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 [&_svg]:text-muted-foreground"><span x-text="s(`clearSort`)"></span></div></div>
                                        <template x-if="canEditColumns">
                                            <div>
                                                <div data-slot="dropdown-menu-separator" role="separator" aria-orientation="horizontal" class="-mx-1.5 my-1.5 h-px bg-border"></div>
                                                <div data-slot="dropdown-menu-group" role="group" ><div data-slot="dropdown-menu-item" role="menuitem" data-variant="default" x-bind="item"
        x-on:click="openColumn(column)" class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control px-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 [&_svg]:text-muted-foreground"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"/>
  <path d="m15 5 4 4"/>
</svg><span x-text="s(`editColumn`)"></span></div>
                                                    <div data-slot="dropdown-menu-item" role="menuitem" data-variant="default" x-bind="item"
        x-bind:data-disabled="colMoveOff(ci, -1)" x-on:click="moveColumn(ci, -1)" class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control px-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 [&_svg]:text-muted-foreground"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="m12 19-7-7 7-7"/>
  <path d="M19 12H5"/>
</svg><span x-text="s(`moveLeft`)"></span></div>
                                                    <div data-slot="dropdown-menu-item" role="menuitem" data-variant="default" x-bind="item"
        x-bind:data-disabled="colMoveOff(ci, 1)" x-on:click="moveColumn(ci, 1)" class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control px-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 [&_svg]:text-muted-foreground"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M5 12h14"/>
  <path d="m12 5 7 7-7 7"/>
</svg><span x-text="s(`moveRight`)"></span></div></div>
                                                <div data-slot="dropdown-menu-separator" role="separator" aria-orientation="horizontal" class="-mx-1.5 my-1.5 h-px bg-border"></div>
                                                <div data-slot="dropdown-menu-item" role="menuitem" data-variant="danger" x-bind="item"
        x-on:click="deleteColumn(column)" class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control px-2.5 text-body-sm outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 text-nq-danger-text [&_svg]:text-current"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M10 11v6"/>
  <path d="M14 11v6"/>
  <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/>
  <path d="M3 6h18"/>
  <path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
</svg><span x-text="s(`deleteColumn`)"></span></div>
                                            </div>
                                        </template></div>
</template></div>
                            </div>
                        </div>
                    </template>
                    <div role="columnheader" class="table-cell w-10 px-1"></div>
                </div>
            </div>
            <div role="rowgroup" class="table-row-group">
                <template x-for="(row, ri) in view" :key="row.id">
                    <div role="row" data-slot="content-table-row" x-bind:aria-rowindex="ri + 2" x-bind:aria-selected="isSelected(row)" x-bind:data-state="rowState(row)"
                        class="table-row group border-b border-border last:border-b-0 hover:bg-nq-hover data-[state=selected]:bg-nq-selected">
                        <div role="gridcell" class="table-cell w-10 px-3 align-middle">
                            <template x-if="editable"><button type="button" role="checkbox" data-slot="checkbox"
    x-bind="boxBind(`row`, row.id)" x-bind:aria-label="s(`selectRow`, n(ri + 1))" class="relative inline-flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-nq-line-strong bg-card text-primary-foreground outline-none transition-colors duration-150 ease-nq data-checked:border-primary data-checked:bg-primary data-indeterminate:border-primary data-indeterminate:bg-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus data-disabled:cursor-not-allowed data-disabled:opacity-50 after:absolute after:-inset-1">
    <span data-slot="checkbox-indicator" class="flex items-center justify-center [&_svg]:size-3 [&_svg]:stroke-3">
        <svg aria-hidden="true" class="hidden [[data-indeterminate]_&]:block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M5 12h14"/>
</svg>        <svg aria-hidden="true" class="hidden [[data-checked]_&]:block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M20 6 9 17l-5-5"/>
</svg>    </span>
</button>
</template>
                            <template x-if="! editable"><span class="text-caption text-muted-foreground tabular-nums" x-text="n(ri + 1)"></span></template>
                        </div>
                        <template x-for="(column, ci) in columns" :key="column.id">
                            <div role="gridcell" x-bind:tabindex="tabindex(row, ri, ci)" x-bind:data-row="row.id" x-bind:data-col="ci"
                                x-bind:aria-invalid="cellInvalid(row, column)" x-bind:aria-label="cellAria(row, column, ri)" x-bind:title="cellTitle(row, column)"
                                x-bind:style="widthStyle(column, true)" x-bind:class="cellClass(row, column)"
                                x-on:focus="onCellFocus($event, row, ci)" x-on:keydown="onCellKey($event, row, ci)" x-on:click="onCellClick($event, row, ci, column)"
                                class="table-cell relative h-row border-s border-border px-3 align-middle outline-none first:border-s-0 focus:outline-2 focus:-outline-offset-2 focus:outline-nq-focus">
                                <template x-if="cellKind(row, column, ci) === `checkbox`">
                                    <button type="button" role="checkbox" data-slot="checkbox"
    x-bind="boxBind(`cell`, row.id, column.id)" x-bind:aria-label="cellLabel(row, column, ri)" class="relative inline-flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-nq-line-strong bg-card text-primary-foreground outline-none transition-colors duration-150 ease-nq data-checked:border-primary data-checked:bg-primary data-indeterminate:border-primary data-indeterminate:bg-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus data-disabled:cursor-not-allowed data-disabled:opacity-50 after:absolute after:-inset-1">
    <span data-slot="checkbox-indicator" class="flex items-center justify-center [&_svg]:size-3 [&_svg]:stroke-3">
        <svg aria-hidden="true" class="hidden [[data-indeterminate]_&]:block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M5 12h14"/>
</svg>        <svg aria-hidden="true" class="hidden [[data-checked]_&]:block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M20 6 9 17l-5-5"/>
</svg>    </span>
</button>
                                </template>
                                <template x-if="cellKind(row, column, ci) === `choice`">
                                    <div x-data="nqPopover(false)" x-id="['nq-popover']" class="contents">
                                        <div data-choice-trigger x-ref="trigger" role="button" aria-haspopup="dialog" x-bind:aria-expanded="open" x-bind:aria-label="column.label" x-on:click="editable ? toggle() : null"
                                            class="flex min-h-6 w-full min-w-0 items-center outline-none">
                                            <span class="contents">
<template x-if="displayKind(column, row.cells[column.id]) === `empty`"><span class="text-muted-foreground/60" aria-hidden="true">—</span></template>
<template x-if="displayKind(column, row.cells[column.id]) === `number`"><span class="block w-full text-end tabular-nums" x-text="numberText(row.cells[column.id])"></span></template>
<template x-if="displayKind(column, row.cells[column.id]) === `date`"><span x-text="dateText(row.cells[column.id])"></span></template>
<template x-if="displayKind(column, row.cells[column.id]) === `url`">
    <span class="flex min-w-0 items-center gap-1.5">
        <bdi dir="ltr" class="min-w-0 truncate text-start underline decoration-nq-line-strong underline-offset-4" x-text="urlText(row.cells[column.id])"></bdi>
        <template x-if="isLink(row.cells[column.id])">
            <a x-bind:href="textOf(row.cells[column.id])" target="_blank" rel="noopener noreferrer" tabindex="-1" x-bind:aria-label="openLabel(ri)" x-on:click.stop
                class="shrink-0 rounded-[4px] text-muted-foreground hover:text-foreground"><svg aria-hidden="true" class="size-3.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M15 3h6v6"/>
  <path d="M10 14 21 3"/>
  <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
</svg></a>
        </template>
    </span>
</template>
<template x-if="displayKind(column, row.cells[column.id]) === `select`">
    <span data-slot="badge" x-bind:style="tagStyle(column, row.cells[column.id])" x-text="optionLabel(column, row.cells[column.id])"
        class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border border-transparent bg-[var(--tag-soft)] px-1.5 text-caption font-medium text-[var(--tag-solid)]"></span>
</template>
<template x-if="displayKind(column, row.cells[column.id]) === `tags`">
    <span class="flex min-w-0 flex-nowrap items-center gap-1 overflow-hidden">
        <template x-for="v in tagList(row.cells[column.id])" :key="v">
            <span data-slot="badge" x-bind:style="tagStyle(column, v)" x-text="optionLabel(column, v)"
                class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border border-transparent bg-[var(--tag-soft)] px-1.5 text-caption font-medium text-[var(--tag-solid)]"></span>
        </template>
    </span>
</template>
<template x-if="displayKind(column, row.cells[column.id]) === `text`"><span class="block min-w-0 truncate" dir="auto" x-text="textOf(row.cells[column.id])"></span></template>
</span>
                                        </div>
                                        <template x-teleport="body">
                                            <div data-slot="popover-content" x-bind="popup" x-init="popupEl = $el" x-nq-presence="open" x-anchor.bottom-start.offset.6="$refs.trigger"
                                                class="z-50 w-56 max-w-[var(--available-width)] rounded-floating border border-border bg-popover p-1 text-body-sm text-popover-foreground shadow-floating outline-none transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0">
                                                <p x-show="noOptions(column)" class="px-2 py-1.5 text-caption text-muted-foreground" x-text="s(`noOptions`)"></p>
                                                <ul role="listbox" x-bind:aria-label="column.label" x-bind:aria-multiselectable="isMulti(column)" class="flex max-h-60 flex-col overflow-y-auto">
                                                    <template x-for="o in optionList(column)" :key="o.value">
                                                        <li role="presentation">
                                                            <button type="button" role="option" x-bind:aria-selected="isChosen(row, column, o.value)" x-on:click="pick(row, column, o.value); isMulti(column) ? null : close()"
                                                                class="flex h-control-sm w-full items-center gap-2 rounded-[4px] px-2 text-start outline-none hover:bg-nq-hover focus-visible:bg-nq-hover focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-nq-focus">
                                                                <span class="flex size-4 shrink-0 items-center justify-center"><svg aria-hidden="true" x-show="isChosen(row, column, o.value)" style="display: none" class="size-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M20 6 9 17l-5-5"/>
</svg></span>
                                                                <span data-slot="badge" x-bind:style="tagStyle(column, o.value)" x-text="o.label"
                                                                    class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border border-transparent bg-[var(--tag-soft)] px-1.5 text-caption font-medium text-[var(--tag-solid)]"></span>
                                                            </button>
                                                        </li>
                                                    </template>
                                                </ul>
                                                <button type="button" x-show="hasValue(row, column)" style="display: none" x-on:click="clearChoice(row, column); close()" x-text="s(`clear`)"
                                                    class="mt-1 flex h-control-sm w-full items-center rounded-[4px] border-t border-border px-2 text-caption text-muted-foreground outline-none hover:bg-nq-hover focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-nq-focus"></button>
                                            </div>
                                        </template>
                                    </div>
                                </template>
                                <template x-if="cellKind(row, column, ci) === `editing`">
                                    <div>
                                        <span class="invisible"><span class="contents">
<template x-if="displayKind(column, row.cells[column.id]) === `empty`"><span class="text-muted-foreground/60" aria-hidden="true">—</span></template>
<template x-if="displayKind(column, row.cells[column.id]) === `number`"><span class="block w-full text-end tabular-nums" x-text="numberText(row.cells[column.id])"></span></template>
<template x-if="displayKind(column, row.cells[column.id]) === `date`"><span x-text="dateText(row.cells[column.id])"></span></template>
<template x-if="displayKind(column, row.cells[column.id]) === `url`">
    <span class="flex min-w-0 items-center gap-1.5">
        <bdi dir="ltr" class="min-w-0 truncate text-start underline decoration-nq-line-strong underline-offset-4" x-text="urlText(row.cells[column.id])"></bdi>
        <template x-if="isLink(row.cells[column.id])">
            <a x-bind:href="textOf(row.cells[column.id])" target="_blank" rel="noopener noreferrer" tabindex="-1" x-bind:aria-label="openLabel(ri)" x-on:click.stop
                class="shrink-0 rounded-[4px] text-muted-foreground hover:text-foreground"><svg aria-hidden="true" class="size-3.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M15 3h6v6"/>
  <path d="M10 14 21 3"/>
  <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
</svg></a>
        </template>
    </span>
</template>
<template x-if="displayKind(column, row.cells[column.id]) === `select`">
    <span data-slot="badge" x-bind:style="tagStyle(column, row.cells[column.id])" x-text="optionLabel(column, row.cells[column.id])"
        class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border border-transparent bg-[var(--tag-soft)] px-1.5 text-caption font-medium text-[var(--tag-solid)]"></span>
</template>
<template x-if="displayKind(column, row.cells[column.id]) === `tags`">
    <span class="flex min-w-0 flex-nowrap items-center gap-1 overflow-hidden">
        <template x-for="v in tagList(row.cells[column.id])" :key="v">
            <span data-slot="badge" x-bind:style="tagStyle(column, v)" x-text="optionLabel(column, v)"
                class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border border-transparent bg-[var(--tag-soft)] px-1.5 text-caption font-medium text-[var(--tag-solid)]"></span>
        </template>
    </span>
</template>
<template x-if="displayKind(column, row.cells[column.id]) === `text`"><span class="block min-w-0 truncate" dir="auto" x-text="textOf(row.cells[column.id])"></span></template>
</span>
</span>
                                        <input x-init="startEditor($el, row, column)" x-bind:type="editorType(column)" x-bind:inputmode="editorMode(column)" x-bind:dir="editorDir(column)" x-bind:aria-label="cellLabel(row, column, ri)"
                                            x-bind:class="editorClass(column)" x-on:keydown="onEditorKey($event, row, ci)" x-on:blur="finishEdit(row.id, ci, $el.value, `none`)"
                                            class="absolute inset-0 size-full min-w-0 bg-card px-3 text-body-sm text-foreground outline-2 -outline-offset-2 outline-nq-focus">
                                    </div>
                                </template>
                                <template x-if="cellKind(row, column, ci) === `view`"><span class="contents">
<template x-if="displayKind(column, row.cells[column.id]) === `empty`"><span class="text-muted-foreground/60" aria-hidden="true">—</span></template>
<template x-if="displayKind(column, row.cells[column.id]) === `number`"><span class="block w-full text-end tabular-nums" x-text="numberText(row.cells[column.id])"></span></template>
<template x-if="displayKind(column, row.cells[column.id]) === `date`"><span x-text="dateText(row.cells[column.id])"></span></template>
<template x-if="displayKind(column, row.cells[column.id]) === `url`">
    <span class="flex min-w-0 items-center gap-1.5">
        <bdi dir="ltr" class="min-w-0 truncate text-start underline decoration-nq-line-strong underline-offset-4" x-text="urlText(row.cells[column.id])"></bdi>
        <template x-if="isLink(row.cells[column.id])">
            <a x-bind:href="textOf(row.cells[column.id])" target="_blank" rel="noopener noreferrer" tabindex="-1" x-bind:aria-label="openLabel(ri)" x-on:click.stop
                class="shrink-0 rounded-[4px] text-muted-foreground hover:text-foreground"><svg aria-hidden="true" class="size-3.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M15 3h6v6"/>
  <path d="M10 14 21 3"/>
  <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
</svg></a>
        </template>
    </span>
</template>
<template x-if="displayKind(column, row.cells[column.id]) === `select`">
    <span data-slot="badge" x-bind:style="tagStyle(column, row.cells[column.id])" x-text="optionLabel(column, row.cells[column.id])"
        class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border border-transparent bg-[var(--tag-soft)] px-1.5 text-caption font-medium text-[var(--tag-solid)]"></span>
</template>
<template x-if="displayKind(column, row.cells[column.id]) === `tags`">
    <span class="flex min-w-0 flex-nowrap items-center gap-1 overflow-hidden">
        <template x-for="v in tagList(row.cells[column.id])" :key="v">
            <span data-slot="badge" x-bind:style="tagStyle(column, v)" x-text="optionLabel(column, v)"
                class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border border-transparent bg-[var(--tag-soft)] px-1.5 text-caption font-medium text-[var(--tag-solid)]"></span>
        </template>
    </span>
</template>
<template x-if="displayKind(column, row.cells[column.id]) === `text`"><span class="block min-w-0 truncate" dir="auto" x-text="textOf(row.cells[column.id])"></span></template>
</span>
</template>
                            </div>
                        </template>
                        <div role="gridcell" class="table-cell w-10 px-1 align-middle">
                            <template x-if="editable">
                                <div data-slot="dropdown-menu" x-data="nqDropdownMenu(false)" x-modelable="open" class="contents"><button data-slot="dropdown-menu-trigger"
     type="button"                         x-bind="trigger" x-ref="trigger" x-bind:aria-label="s(`rowActions`, n(ri + 1))" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 text-foreground hover:bg-nq-hover size-control-sm p-0 opacity-60 group-hover:opacity-100 focus-visible:opacity-100">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="1"/>
  <circle cx="19" cy="12" r="1"/>
  <circle cx="5" cy="12" r="1"/>
</svg></button>
                                    <template x-teleport="body">
    <div data-slot="dropdown-menu-content" x-bind="popup" x-init="popupEl = $el" x-nq-presence="open" x-anchor.bottom-end.offset.4="$refs.trigger"
        class="z-50 overflow-hidden rounded-floating border border-border bg-popover p-1.5 text-popover-foreground shadow-floating outline-none max-h-[var(--available-height)] overflow-y-auto transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0 min-w-48"><div data-slot="dropdown-menu-group" role="group" ><div data-slot="dropdown-menu-item" role="menuitem" data-variant="default" x-bind="item"
        x-on:click="addRowAt(row, 0)" class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control px-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 [&_svg]:text-muted-foreground"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M5 12h14"/>
  <path d="M12 5v14"/>
</svg><span x-text="s(`insertAbove`)"></span></div>
                                            <div data-slot="dropdown-menu-item" role="menuitem" data-variant="default" x-bind="item"
        x-on:click="addRowAt(row, 1)" class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control px-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 [&_svg]:text-muted-foreground"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M5 12h14"/>
  <path d="M12 5v14"/>
</svg><span x-text="s(`insertBelow`)"></span></div>
                                            <div data-slot="dropdown-menu-item" role="menuitem" data-variant="default" x-bind="item"
        x-on:click="duplicateRow(row)" class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control px-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 [&_svg]:text-muted-foreground"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <rect width="14" height="14" x="8" y="8" rx="2" ry="2"/>
  <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/>
</svg><span x-text="s(`duplicate`)"></span></div></div>
                                        <div data-slot="dropdown-menu-separator" role="separator" aria-orientation="horizontal" class="-mx-1.5 my-1.5 h-px bg-border"></div>
                                        <div data-slot="dropdown-menu-group" role="group" ><div data-slot="dropdown-menu-item" role="menuitem" data-variant="default" x-bind="item"
        x-bind:data-disabled="rowMoveOff(row, -1)" x-on:click="moveRow(row, -1)" class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control px-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 [&_svg]:text-muted-foreground"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="m5 12 7-7 7 7"/>
  <path d="M12 19V5"/>
</svg><span x-text="s(`moveUp`)"></span></div>
                                            <div data-slot="dropdown-menu-item" role="menuitem" data-variant="default" x-bind="item"
        x-bind:data-disabled="rowMoveOff(row, 1)" x-on:click="moveRow(row, 1)" class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control px-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 [&_svg]:text-muted-foreground"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M12 5v14"/>
  <path d="m19 12-7 7-7-7"/>
</svg><span x-text="s(`moveDown`)"></span></div></div>
                                        <div data-slot="dropdown-menu-separator" role="separator" aria-orientation="horizontal" class="-mx-1.5 my-1.5 h-px bg-border"></div>
                                        <div data-slot="dropdown-menu-item" role="menuitem" data-variant="danger" x-bind="item"
        x-on:click="deleteRows([row.id])" class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control px-2.5 text-body-sm outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 text-nq-danger-text [&_svg]:text-current"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M10 11v6"/>
  <path d="M14 11v6"/>
  <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/>
  <path d="M3 6h18"/>
  <path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
</svg><span x-text="s(`delete`)"></span></div></div>
</template></div>
                            </template>
                        </div>
                    </div>
                </template>
            </div>
            <div role="rowgroup" data-slot="content-table-footer" x-show="view.length > 0" class="table-footer-group border-t border-border bg-secondary/50 text-caption text-muted-foreground">
                <div role="row" class="table-row">
                    <div role="gridcell" class="table-cell px-3 py-1.5"></div>
                    <template x-for="column in columns" :key="column.id">
                        <div role="gridcell" class="table-cell border-s border-border px-3 py-1.5 first:border-s-0">
                            <span x-show="isSum(column)" style="display: none" class="flex justify-between gap-2"><span x-text="s(`sum`)"></span><span class="tabular-nums text-foreground" x-text="summaryText(column)"></span></span>
                            <span x-show="! isSum(column)" x-text="summaryText(column)"></span>
                        </div>
                    </template>
                    <div role="gridcell" class="table-cell"></div>
                </div>
            </div>
        </div>
        <div x-show="noMatches" style="display: none" data-slot="empty-state" class="flex flex-col items-center justify-center gap-3 border-t border-border px-6 py-12 text-center">
            <span data-slot="state-icon" class="inline-flex size-10 items-center justify-center rounded-control border border-border bg-card text-muted-foreground [&_svg]:size-5"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="m21 21-4.34-4.34"/>
  <circle cx="11" cy="11" r="8"/>
</svg></span>
            <p class="text-label text-foreground" x-text="s(`noMatches`)"></p>
            <button data-slot="button"
     type="button"                         x-on:click="query = ``" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 border-border bg-card text-foreground hover:bg-nq-hover h-control px-[var(--nq-control-pad)]">
        <span x-text="s(`clearSearch`)"></span></button>
        </div>
    </div>
    <div class="flex flex-wrap items-center justify-between gap-2 text-caption text-muted-foreground">
        <span x-bind:id="$id(`nq-ct`, `hint`)" x-text="hintText()"></span>
        <span x-text="rowCountText()"></span>
    </div>
    <div class="sr-only" role="status" aria-live="polite" x-text="announce"></div>
    <div data-slot="dialog" x-data="nqDialog(false)" x-modelable="open" x-id="['nq-dialog']" x-model="draftOpen" class="contents">
    <template x-teleport="body">
    <div data-slot="dialog-portal">
        <div data-slot="dialog-backdrop" x-nq-presence="open" x-on:click="close()" class="fixed inset-0 z-50 bg-nq-fg/15 dark:bg-nq-bg/60 transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0"></div>
        <div data-slot="dialog-content" x-bind="popup" x-nq-presence="open" x-trap.noscroll="open"
            class="fixed inset-0 z-50 m-auto grid h-fit w-[calc(100%-2rem)] gap-4 rounded-floating border border-border bg-popover p-6 text-popover-foreground outline-none max-h-[calc(100dvh-2rem)] overflow-y-auto transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0 max-w-md">
            <div data-slot="dialog-header" class="flex flex-col gap-1.5 pe-8 text-start"><h2 data-slot="dialog-title" :id="$id('nq-dialog', 'title')" x-text="draftTitle" class="text-h3 text-foreground"></h2>
                <p data-slot="dialog-description" :id="$id('nq-dialog', 'description')" class="text-body-sm text-muted-foreground sr-only"><span x-text="s(`columnName`)"></span></p></div>
            <form class="grid gap-4" x-on:submit.prevent="applyColumn()">
                <div class="grid gap-1.5">
                    <label class="text-label text-foreground" x-bind:for="$id(`nq-ct`, `name`)" x-text="s(`columnName`)"></label>
                    <input type="text" x-bind:id="$id(`nq-ct`, `name`)" x-model="draft.label" class="h-control w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus">
                </div>
                <div class="grid gap-1.5">
                    <label class="text-label text-foreground" x-bind:for="$id(`nq-ct`, `type`)" x-text="s(`columnType`)"></label>
                    <select x-bind:id="$id(`nq-ct`, `type`)" x-model="draft.type" class="h-control w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus">
                        <template x-for="type in columnTypes()" :key="type"><option x-bind:value="type" x-text="typeLabel(type)"></option></template>
                    </select>
                </div>
                <div class="grid gap-1.5" x-show="draftHasOptions" style="display: none">
                    <label class="text-label text-foreground" x-bind:for="$id(`nq-ct`, `options`)" x-text="s(`options`)"></label>
                    <textarea rows="4" x-bind:id="$id(`nq-ct`, `options`)" x-model="draft.options" class="min-h-20 py-2 w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus"></textarea>
                    <p class="text-caption text-muted-foreground" x-text="s(`optionsHint`)"></p>
                </div>
                <label class="flex items-center gap-2 text-body-sm text-foreground">
                    <button type="button" role="checkbox" data-slot="checkbox" x-data="nqCheckbox(false, false)" x-modelable="checked" x-bind="root"
    aria-checked="false"
     data-unchecked                 x-model="draft.required" class="relative inline-flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-nq-line-strong bg-card text-primary-foreground outline-none transition-colors duration-150 ease-nq data-checked:border-primary data-checked:bg-primary data-indeterminate:border-primary data-indeterminate:bg-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus data-disabled:cursor-not-allowed data-disabled:opacity-50 after:absolute after:-inset-1">
    <span data-slot="checkbox-indicator" class="flex items-center justify-center [&_svg]:size-3 [&_svg]:stroke-3" x-show="checked || indeterminate"  style="display: none" >
        <svg aria-hidden="true" x-show="indeterminate" style="display: none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M5 12h14"/>
</svg>        <svg aria-hidden="true" x-show="! indeterminate" style="" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M20 6 9 17l-5-5"/>
</svg>    </span>
    </button>
                    <span x-text="s(`required`)"></span>
                </label>
                <div data-slot="dialog-footer" class="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end"><button data-slot="button"
     type="button"                         x-on:click="draftOpen = false" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 border-border bg-card text-foreground hover:bg-nq-hover h-control px-[var(--nq-control-pad)]">
        <span x-text="s(`cancel`)"></span></button>
                    <button data-slot="button"
     type="submit"                         x-bind:disabled="draftInvalid" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-[color-mix(in_oklab,var(--nq-action)_88%,var(--nq-fg))] h-control px-[var(--nq-control-pad)]">
        <span x-text="s(`saveColumn`)"></span></button></div>
            </form>
                            <button type="button" data-slot="dialog-close" x-on:click="close()" aria-label="Close"
                    class="absolute end-3 top-3 inline-flex size-8 items-center justify-center rounded-control text-muted-foreground transition-colors duration-150 hover:bg-nq-hover hover:text-foreground focus-visible:outline-2 focus-visible:outline-nq-focus [&_svg]:size-4"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M18 6 6 18"/>
  <path d="m6 6 12 12"/>
</svg></button>
                    </div>
    </div>
</template>
</div>
</div>
</div>
```
