beta
Data table — <mv-data-table>
Full-featured data table around a .mv-table: column sorting, accent-insensitive search, value filters, a column visibility menu, row selection (indeterminate header checkbox, Shift + click for ranges) with a bulk-actions bar, pagination with rows per page, and an empty state.
| Category | Blocks |
|---|---|
| Type | Web Component (<mv-data-table>) |
| Status | beta |
| Also installs | checkbox, menu, popover, pagination, table |
| Keywords | data-table, datagrid, table, sort, filter, search, pagination, selection, bulk-actions, columns |
When to use
- Users must sort, search, filter and paginate a list of records in an admin or back-office screen
- Rows need multi-selection with Shift + click ranges and a bulk-actions bar
- Users should choose which columns are visible on a wide dataset
Avoid when
- The data is a small static table that needs no selection or column controls → use Table instead
- Thousands of records or server-side data; every row must be in the initial HTML and is searched and sorted in the browser
Install
node scripts/add.mjs data-table --out ./src/marvelousAI agent with the Marvelous UI MCP server: install_components({ slugs: ["data-table"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).
Files copied (dependencies included): tokens/tokens.css, core/base.css, core/dismiss.js, core/dom.js, core/element.js, core/focus.js, core/motion.js, core/position.js, components/data-table/data-table.js, components/data-table/data-table.css, components/checkbox/checkbox.css, components/menu/menu.js, components/menu/menu.css, components/popover/popover.js, components/popover/popover.css, components/pagination/pagination.js, components/pagination/pagination.css, components/table/table.css, components/table/table.js.
Usage
Canonical markup — start from it and customize with attributes, data-* and CSS variables:
<div id="dt-demo" style="width:min(100%,64rem);margin-inline:auto">
<mv-data-table page-size="8" label="Recent orders">
<div class="mv-data-table-toolbar">
<div class="mv-input-group" data-size="sm">
<label class="mv-input-group-addon" for="dt-demo-q"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg><span class="mv-sr-only">Search</span></label>
<input id="dt-demo-q" class="mv-input" type="search" placeholder="Search orders or customers…" data-dt-search autocomplete="off">
</div>
<select class="mv-select" data-size="sm" data-dt-filter="status" aria-label="Filter by status">
<option value="">All statuses</option>
<option value="paid">Paid</option>
<option value="pending">Pending</option>
<option value="shipped">Shipped</option>
<option value="refunded">Refunded</option>
<option value="failed">Failed</option>
</select>
<div class="mv-data-table-toolbar-end">
<mv-menu data-dt-columns placement="bottom-end">
<button class="mv-button" data-variant="outline" data-size="sm" type="button"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h16"/><path d="M9 4v16M15 4v16" opacity=".5"/></svg>Columns</button>
<div data-content style="--mv-menu-width:12rem"></div>
</mv-menu>
<button class="mv-button" data-size="sm" type="button" data-dt-demo-export><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v12m-5-5 5 5 5-5M5 21h14"/></svg><span data-dt-label>Export</span></button>
</div>
</div>
<div class="mv-table-wrap">
<table class="mv-table">
<thead>
<tr>
<th scope="col" data-dt-select></th>
<th scope="col" data-key="id" data-sort="text">Order</th>
<th scope="col" data-key="client" data-sort="text">Customer</th>
<th scope="col" data-key="status" data-sort="text">Status</th>
<th scope="col" data-key="channel" data-sort="text">Channel</th>
<th scope="col" data-key="date" data-sort="date">Date</th>
<th scope="col" data-key="items" data-sort="number" data-align="end">Items</th>
<th scope="col" data-key="amount" data-sort="number" data-align="end">Amount</th>
<th scope="col"><span class="mv-sr-only">Actions</span></th>
</tr>
</thead>
<tbody>
<tr data-id="ORD-4821">
<td></td>
<td><span class="mv-data-table-mono">ORD-4821</span></td>
<td data-value="Camila Rossi"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:200" aria-hidden="true"><span class="mv-avatar-fallback">CR</span></span><div><b>Camila Rossi</b><small>[email protected]</small></div></div></td>
<td data-value="paid"><span class="mv-badge" data-variant="success" data-size="sm">Paid</span></td>
<td class="mv-table-muted">Online store</td>
<td data-value="2026-09-22" class="mv-table-muted"><time datetime="2026-09-22">Sep 22, 2026</time></td>
<td data-align="end" data-value="6">6</td>
<td data-align="end" data-value="111.83"><b>$111.83</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4821" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4820">
<td></td>
<td><span class="mv-data-table-mono">ORD-4820</span></td>
<td data-value="Isabel Moreno"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:280" aria-hidden="true"><span class="mv-avatar-fallback">IM</span></span><div><b>Isabel Moreno</b><small>[email protected]</small></div></div></td>
<td data-value="paid"><span class="mv-badge" data-variant="success" data-size="sm">Paid</span></td>
<td class="mv-table-muted">Online store</td>
<td data-value="2026-09-22" class="mv-table-muted"><time datetime="2026-09-22">Sep 22, 2026</time></td>
<td data-align="end" data-value="3">3</td>
<td data-align="end" data-value="351.32"><b>$351.32</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4820" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4819">
<td></td>
<td><span class="mv-data-table-mono">ORD-4819</span></td>
<td data-value="Kwame Boateng"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:160" aria-hidden="true"><span class="mv-avatar-fallback">KB</span></span><div><b>Kwame Boateng</b><small>[email protected]</small></div></div></td>
<td data-value="refunded"><span class="mv-badge" data-variant="secondary" data-size="sm">Refunded</span></td>
<td class="mv-table-muted">London store</td>
<td data-value="2026-09-21" class="mv-table-muted"><time datetime="2026-09-21">Sep 21, 2026</time></td>
<td data-align="end" data-value="1">1</td>
<td data-align="end" data-value="151.54"><b>$151.54</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4819" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4818">
<td></td>
<td><span class="mv-data-table-mono">ORD-4818</span></td>
<td data-value="Sofia Nguyen"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:320" aria-hidden="true"><span class="mv-avatar-fallback">SN</span></span><div><b>Sofia Nguyen</b><small>[email protected]</small></div></div></td>
<td data-value="pending"><span class="mv-badge" data-variant="warning" data-size="sm">Pending</span></td>
<td class="mv-table-muted">London store</td>
<td data-value="2026-09-20" class="mv-table-muted"><time datetime="2026-09-20">Sep 20, 2026</time></td>
<td data-align="end" data-value="5">5</td>
<td data-align="end" data-value="167.69"><b>$167.69</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4818" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4817">
<td></td>
<td><span class="mv-data-table-mono">ORD-4817</span></td>
<td data-value="Tom Grant"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:240" aria-hidden="true"><span class="mv-avatar-fallback">TG</span></span><div><b>Tom Grant</b><small>[email protected]</small></div></div></td>
<td data-value="paid"><span class="mv-badge" data-variant="success" data-size="sm">Paid</span></td>
<td class="mv-table-muted">Online store</td>
<td data-value="2026-09-20" class="mv-table-muted"><time datetime="2026-09-20">Sep 20, 2026</time></td>
<td data-align="end" data-value="2">2</td>
<td data-align="end" data-value="369.71"><b>$369.71</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4817" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4816">
<td></td>
<td><span class="mv-data-table-mono">ORD-4816</span></td>
<td data-value="Lena Fischer"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:20" aria-hidden="true"><span class="mv-avatar-fallback">LF</span></span><div><b>Lena Fischer</b><small>[email protected]</small></div></div></td>
<td data-value="shipped"><span class="mv-badge" data-variant="info" data-size="sm">Shipped</span></td>
<td class="mv-table-muted">Online store</td>
<td data-value="2026-09-19" class="mv-table-muted"><time datetime="2026-09-19">Sep 19, 2026</time></td>
<td data-align="end" data-value="2">2</td>
<td data-align="end" data-value="264.74"><b>$264.74</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4816" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4815">
<td></td>
<td><span class="mv-data-table-mono">ORD-4815</span></td>
<td data-value="Hugo Larsen"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:110" aria-hidden="true"><span class="mv-avatar-fallback">HL</span></span><div><b>Hugo Larsen</b><small>[email protected]</small></div></div></td>
<td data-value="shipped"><span class="mv-badge" data-variant="info" data-size="sm">Shipped</span></td>
<td class="mv-table-muted">Mobile app</td>
<td data-value="2026-09-18" class="mv-table-muted"><time datetime="2026-09-18">Sep 18, 2026</time></td>
<td data-align="end" data-value="4">4</td>
<td data-align="end" data-value="100.83"><b>$100.83</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4815" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4814">
<td></td>
<td><span class="mv-data-table-mono">ORD-4814</span></td>
<td data-value="Chloe Martin"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:350" aria-hidden="true"><span class="mv-avatar-fallback">CM</span></span><div><b>Chloe Martin</b><small>[email protected]</small></div></div></td>
<td data-value="shipped"><span class="mv-badge" data-variant="info" data-size="sm">Shipped</span></td>
<td class="mv-table-muted">Mobile app</td>
<td data-value="2026-09-17" class="mv-table-muted"><time datetime="2026-09-17">Sep 17, 2026</time></td>
<td data-align="end" data-value="5">5</td>
<td data-align="end" data-value="373.11"><b>$373.11</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4814" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4813">
<td></td>
<td><span class="mv-data-table-mono">ORD-4813</span></td>
<td data-value="Mehdi Haddad"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:60" aria-hidden="true"><span class="mv-avatar-fallback">MH</span></span><div><b>Mehdi Haddad</b><small>[email protected]</small></div></div></td>
<td data-value="paid"><span class="mv-badge" data-variant="success" data-size="sm">Paid</span></td>
<td class="mv-table-muted">Marketplace</td>
<td data-value="2026-09-17" class="mv-table-muted"><time datetime="2026-09-17">Sep 17, 2026</time></td>
<td data-align="end" data-value="2">2</td>
<td data-align="end" data-value="373.29"><b>$373.29</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4813" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4812">
<td></td>
<td><span class="mv-data-table-mono">ORD-4812</span></td>
<td data-value="Zoe Brooks"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:300" aria-hidden="true"><span class="mv-avatar-fallback">ZB</span></span><div><b>Zoe Brooks</b><small>[email protected]</small></div></div></td>
<td data-value="paid"><span class="mv-badge" data-variant="success" data-size="sm">Paid</span></td>
<td class="mv-table-muted">Online store</td>
<td data-value="2026-09-16" class="mv-table-muted"><time datetime="2026-09-16">Sep 16, 2026</time></td>
<td data-align="end" data-value="5">5</td>
<td data-align="end" data-value="460.93"><b>$460.93</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4812" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4811">
<td></td>
<td><span class="mv-data-table-mono">ORD-4811</span></td>
<td data-value="James Miller"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:190" aria-hidden="true"><span class="mv-avatar-fallback">JM</span></span><div><b>James Miller</b><small>[email protected]</small></div></div></td>
<td data-value="shipped"><span class="mv-badge" data-variant="info" data-size="sm">Shipped</span></td>
<td class="mv-table-muted">London store</td>
<td data-value="2026-09-15" class="mv-table-muted"><time datetime="2026-09-15">Sep 15, 2026</time></td>
<td data-align="end" data-value="5">5</td>
<td data-align="end" data-value="326.77"><b>$326.77</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4811" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4810">
<td></td>
<td><span class="mv-data-table-mono">ORD-4810</span></td>
<td data-value="Emma Park"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:140" aria-hidden="true"><span class="mv-avatar-fallback">EP</span></span><div><b>Emma Park</b><small>[email protected]</small></div></div></td>
<td data-value="shipped"><span class="mv-badge" data-variant="info" data-size="sm">Shipped</span></td>
<td class="mv-table-muted">Marketplace</td>
<td data-value="2026-09-14" class="mv-table-muted"><time datetime="2026-09-14">Sep 14, 2026</time></td>
<td data-align="end" data-value="4">4</td>
<td data-align="end" data-value="307.6"><b>$307.60</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4810" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4809">
<td></td>
<td><span class="mv-data-table-mono">ORD-4809</span></td>
<td data-value="Noah Reyes"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:230" aria-hidden="true"><span class="mv-avatar-fallback">NR</span></span><div><b>Noah Reyes</b><small>[email protected]</small></div></div></td>
<td data-value="paid"><span class="mv-badge" data-variant="success" data-size="sm">Paid</span></td>
<td class="mv-table-muted">Mobile app</td>
<td data-value="2026-09-14" class="mv-table-muted"><time datetime="2026-09-14">Sep 14, 2026</time></td>
<td data-align="end" data-value="6">6</td>
<td data-align="end" data-value="512.1"><b>$512.10</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4809" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4808">
<td></td>
<td><span class="mv-data-table-mono">ORD-4808</span></td>
<td data-value="Maya Das"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:10" aria-hidden="true"><span class="mv-avatar-fallback">MD</span></span><div><b>Maya Das</b><small>[email protected]</small></div></div></td>
<td data-value="paid"><span class="mv-badge" data-variant="success" data-size="sm">Paid</span></td>
<td class="mv-table-muted">Marketplace</td>
<td data-value="2026-09-13" class="mv-table-muted"><time datetime="2026-09-13">Sep 13, 2026</time></td>
<td data-align="end" data-value="4">4</td>
<td data-align="end" data-value="204.75"><b>$204.75</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4808" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4807">
<td></td>
<td><span class="mv-data-table-mono">ORD-4807</span></td>
<td data-value="Yusuf Celik"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:260" aria-hidden="true"><span class="mv-avatar-fallback">YC</span></span><div><b>Yusuf Celik</b><small>[email protected]</small></div></div></td>
<td data-value="shipped"><span class="mv-badge" data-variant="info" data-size="sm">Shipped</span></td>
<td class="mv-table-muted">Online store</td>
<td data-value="2026-09-12" class="mv-table-muted"><time datetime="2026-09-12">Sep 12, 2026</time></td>
<td data-align="end" data-value="1">1</td>
<td data-align="end" data-value="197.1"><b>$197.10</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4807" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4806">
<td></td>
<td><span class="mv-data-table-mono">ORD-4806</span></td>
<td data-value="Mehdi Haddad"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:60" aria-hidden="true"><span class="mv-avatar-fallback">MH</span></span><div><b>Mehdi Haddad</b><small>[email protected]</small></div></div></td>
<td data-value="pending"><span class="mv-badge" data-variant="warning" data-size="sm">Pending</span></td>
<td class="mv-table-muted">London store</td>
<td data-value="2026-09-11" class="mv-table-muted"><time datetime="2026-09-11">Sep 11, 2026</time></td>
<td data-align="end" data-value="2">2</td>
<td data-align="end" data-value="488.94"><b>$488.94</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4806" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4805">
<td></td>
<td><span class="mv-data-table-mono">ORD-4805</span></td>
<td data-value="Hugo Larsen"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:110" aria-hidden="true"><span class="mv-avatar-fallback">HL</span></span><div><b>Hugo Larsen</b><small>[email protected]</small></div></div></td>
<td data-value="paid"><span class="mv-badge" data-variant="success" data-size="sm">Paid</span></td>
<td class="mv-table-muted">Marketplace</td>
<td data-value="2026-09-11" class="mv-table-muted"><time datetime="2026-09-11">Sep 11, 2026</time></td>
<td data-align="end" data-value="5">5</td>
<td data-align="end" data-value="433.63"><b>$433.63</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4805" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4804">
<td></td>
<td><span class="mv-data-table-mono">ORD-4804</span></td>
<td data-value="Lena Fischer"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:20" aria-hidden="true"><span class="mv-avatar-fallback">LF</span></span><div><b>Lena Fischer</b><small>[email protected]</small></div></div></td>
<td data-value="shipped"><span class="mv-badge" data-variant="info" data-size="sm">Shipped</span></td>
<td class="mv-table-muted">London store</td>
<td data-value="2026-09-10" class="mv-table-muted"><time datetime="2026-09-10">Sep 10, 2026</time></td>
<td data-align="end" data-value="5">5</td>
<td data-align="end" data-value="387.7"><b>$387.70</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4804" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4803">
<td></td>
<td><span class="mv-data-table-mono">ORD-4803</span></td>
<td data-value="Isabel Moreno"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:280" aria-hidden="true"><span class="mv-avatar-fallback">IM</span></span><div><b>Isabel Moreno</b><small>[email protected]</small></div></div></td>
<td data-value="shipped"><span class="mv-badge" data-variant="info" data-size="sm">Shipped</span></td>
<td class="mv-table-muted">Online store</td>
<td data-value="2026-09-09" class="mv-table-muted"><time datetime="2026-09-09">Sep 9, 2026</time></td>
<td data-align="end" data-value="4">4</td>
<td data-align="end" data-value="605.59"><b>$605.59</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4803" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4802">
<td></td>
<td><span class="mv-data-table-mono">ORD-4802</span></td>
<td data-value="Camila Rossi"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:200" aria-hidden="true"><span class="mv-avatar-fallback">CR</span></span><div><b>Camila Rossi</b><small>[email protected]</small></div></div></td>
<td data-value="shipped"><span class="mv-badge" data-variant="info" data-size="sm">Shipped</span></td>
<td class="mv-table-muted">London store</td>
<td data-value="2026-09-08" class="mv-table-muted"><time datetime="2026-09-08">Sep 8, 2026</time></td>
<td data-align="end" data-value="5">5</td>
<td data-align="end" data-value="210.58"><b>$210.58</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4802" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4801">
<td></td>
<td><span class="mv-data-table-mono">ORD-4801</span></td>
<td data-value="Tom Grant"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:240" aria-hidden="true"><span class="mv-avatar-fallback">TG</span></span><div><b>Tom Grant</b><small>[email protected]</small></div></div></td>
<td data-value="shipped"><span class="mv-badge" data-variant="info" data-size="sm">Shipped</span></td>
<td class="mv-table-muted">Online store</td>
<td data-value="2026-09-08" class="mv-table-muted"><time datetime="2026-09-08">Sep 8, 2026</time></td>
<td data-align="end" data-value="3">3</td>
<td data-align="end" data-value="569.74"><b>$569.74</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4801" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4800">
<td></td>
<td><span class="mv-data-table-mono">ORD-4800</span></td>
<td data-value="Chloe Martin"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:350" aria-hidden="true"><span class="mv-avatar-fallback">CM</span></span><div><b>Chloe Martin</b><small>[email protected]</small></div></div></td>
<td data-value="paid"><span class="mv-badge" data-variant="success" data-size="sm">Paid</span></td>
<td class="mv-table-muted">Online store</td>
<td data-value="2026-09-07" class="mv-table-muted"><time datetime="2026-09-07">Sep 7, 2026</time></td>
<td data-align="end" data-value="4">4</td>
<td data-align="end" data-value="397.99"><b>$397.99</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4800" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4799">
<td></td>
<td><span class="mv-data-table-mono">ORD-4799</span></td>
<td data-value="Sofia Nguyen"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:320" aria-hidden="true"><span class="mv-avatar-fallback">SN</span></span><div><b>Sofia Nguyen</b><small>[email protected]</small></div></div></td>
<td data-value="shipped"><span class="mv-badge" data-variant="info" data-size="sm">Shipped</span></td>
<td class="mv-table-muted">London store</td>
<td data-value="2026-09-06" class="mv-table-muted"><time datetime="2026-09-06">Sep 6, 2026</time></td>
<td data-align="end" data-value="2">2</td>
<td data-align="end" data-value="98.45"><b>$98.45</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4799" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4798">
<td></td>
<td><span class="mv-data-table-mono">ORD-4798</span></td>
<td data-value="Hugo Larsen"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:110" aria-hidden="true"><span class="mv-avatar-fallback">HL</span></span><div><b>Hugo Larsen</b><small>[email protected]</small></div></div></td>
<td data-value="refunded"><span class="mv-badge" data-variant="secondary" data-size="sm">Refunded</span></td>
<td class="mv-table-muted">London store</td>
<td data-value="2026-09-05" class="mv-table-muted"><time datetime="2026-09-05">Sep 5, 2026</time></td>
<td data-align="end" data-value="2">2</td>
<td data-align="end" data-value="326.83"><b>$326.83</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4798" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4797">
<td></td>
<td><span class="mv-data-table-mono">ORD-4797</span></td>
<td data-value="Hugo Larsen"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:110" aria-hidden="true"><span class="mv-avatar-fallback">HL</span></span><div><b>Hugo Larsen</b><small>[email protected]</small></div></div></td>
<td data-value="shipped"><span class="mv-badge" data-variant="info" data-size="sm">Shipped</span></td>
<td class="mv-table-muted">Marketplace</td>
<td data-value="2026-09-05" class="mv-table-muted"><time datetime="2026-09-05">Sep 5, 2026</time></td>
<td data-align="end" data-value="4">4</td>
<td data-align="end" data-value="567.46"><b>$567.46</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4797" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4796">
<td></td>
<td><span class="mv-data-table-mono">ORD-4796</span></td>
<td data-value="Emma Park"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:140" aria-hidden="true"><span class="mv-avatar-fallback">EP</span></span><div><b>Emma Park</b><small>[email protected]</small></div></div></td>
<td data-value="pending"><span class="mv-badge" data-variant="warning" data-size="sm">Pending</span></td>
<td class="mv-table-muted">Mobile app</td>
<td data-value="2026-09-04" class="mv-table-muted"><time datetime="2026-09-04">Sep 4, 2026</time></td>
<td data-align="end" data-value="4">4</td>
<td data-align="end" data-value="241.16"><b>$241.16</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4796" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
<tr data-id="ORD-4795">
<td></td>
<td><span class="mv-data-table-mono">ORD-4795</span></td>
<td data-value="Kwame Boateng"><div class="mv-data-table-person"><span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:160" aria-hidden="true"><span class="mv-avatar-fallback">KB</span></span><div><b>Kwame Boateng</b><small>[email protected]</small></div></div></td>
<td data-value="paid"><span class="mv-badge" data-variant="success" data-size="sm">Paid</span></td>
<td class="mv-table-muted">Mobile app</td>
<td data-value="2026-09-03" class="mv-table-muted"><time datetime="2026-09-03">Sep 3, 2026</time></td>
<td data-align="end" data-value="6">6</td>
<td data-align="end" data-value="112.11"><b>$112.11</b></td>
<td data-align="end"><button class="mv-button" data-variant="ghost" data-size="icon" type="button" aria-label="Actions for ORD-4795" data-dt-demo-row><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg></button></td>
</tr>
</tbody>
</table>
</div>
<div class="mv-data-table-footer">
<span data-dt-selection aria-live="polite"></span>
<label>Rows per page
<select class="mv-select" data-size="sm" data-dt-page-size>
<option>5</option><option>8</option><option>10</option><option>20</option>
</select>
</label>
<span data-dt-page-info></span>
<mv-pagination data-size="sm" hide-labels siblings="0" data-dt-always label="Orders pagination"></mv-pagination>
</div>
<div class="mv-data-table-bulk" role="toolbar" aria-label="Bulk actions" hidden>
<span data-dt-bulk-count></span>
<button class="mv-button" data-variant="ghost" data-size="sm" type="button" data-dt-action="ship"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 6h11v10H3zM14 10h4l3 3v3h-7"/><circle cx="7" cy="18" r="1.8"/><circle cx="17.5" cy="18" r="1.8"/></svg><span data-dt-label>Mark as shipped</span></button>
<button class="mv-button" data-variant="ghost" data-size="sm" type="button" data-dt-action="export"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v12m-5-5 5 5 5-5M5 21h14"/></svg><span data-dt-label>Export</span></button>
<button class="mv-button" data-variant="ghost" data-size="sm" type="button" data-dt-action="delete" style="color:var(--mv-danger)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 7h16M10 11v6M14 11v6M6 7l1 13h10l1-13M9 7V4h6v3"/></svg><span data-dt-label>Delete</span></button>
<button class="mv-button" data-variant="ghost" data-size="icon" type="button" data-dt-clear aria-label="Clear selection"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg></button>
</div>
</mv-data-table>
<p id="dt-demo-log" role="status" style="margin:.75rem 0 0;min-height:1.25rem;color:var(--mv-fg-muted);font-size:.75rem;text-align:center"></p>
</div>
<script type="module">
const root = document.getElementById("dt-demo");
const table = root?.querySelector("mv-data-table");
const log = root?.querySelector("#dt-demo-log");
table?.addEventListener("mv-action", (e) => {
const { action, rows } = e.detail;
const n = rows.length;
const s = n > 1 ? "s" : "";
if (action === "delete") {
table.removeRows(rows);
log.textContent = `${n} order${s} deleted.`;
} else if (action === "ship") {
for (const row of rows) {
const cell = row.cells[3];
cell.dataset.value = "shipped";
cell.innerHTML = '<span class="mv-badge" data-variant="info" data-size="sm">Shipped</span>';
}
table.clearSelection();
log.textContent = `${n} order${s} marked as shipped.`;
} else if (action === "export") {
log.textContent = `CSV export of ${n} order${s} ready (demo).`;
}
});
root?.querySelector("[data-dt-demo-export]")?.addEventListener("click", () => { log.textContent = "Export of all orders ready (demo)."; });
root?.addEventListener("click", (e) => {
const b = e.target.closest("[data-dt-demo-row]");
if (b) log.textContent = `Actions menu: ${b.closest("tr").dataset.id}`;
});
</script>API
Attributes
| Name | Type | Default | Description |
|---|---|---|---|
page-size | number | 10 | Rows per page (kept in sync with select[data-dt-page-size]). |
label | string | Accessible name for the table (aria-label) if it has none. | |
data-selecting | boolean | Set while at least one row is selected. |
Properties
| Name | Type | Description |
|---|---|---|
selectedRows | HTMLTableRowElement[] | Selected rows (across all pages). |
Methods
| Name | Description |
|---|---|
sortBy(key, direction?) | Sorts by data-key ('ascending' | 'descending'); null clears the sort. |
setColumnVisible(key, visible) | Shows or hides a column. |
clearSelection() | Clears the selection. |
resetFilters() | Clears the search and filters. |
removeRows(rows) | Removes rows (e.g. after a bulk delete). |
render() | Re-renders after cells change. |
Events
| Name | Description |
|---|---|
mv-action | A [data-dt-action] button was clicked. detail: { action, rows }. |
mv-sort | Sort changed. detail: { key, direction }. |
mv-columns | Column visibility changed. detail: { key, visible }. |
mv-render | After each render. detail: { total, page, pages }. |
Content structure
| Name | Description |
|---|---|
table.mv-table | Plain HTML table: th[data-key] names the column, th[data-sort=text|number|date] makes it sortable, th[data-dt-select] adds the checkbox column; td[data-value] provides the raw value for sorting and filtering. |
[data-dt-search] | Search field (matches row text, ignoring accents and case). |
select[data-dt-filter="key"] | Exact-match filter on a column value (empty option = all). |
mv-menu[data-dt-columns] | Menu whose [data-content] panel is filled with column checkboxes (th[data-dt-hideable=false] opts out). |
[data-dt-selection] / [data-dt-page-info] | Auto-filled text: “n of N rows selected”, “1–8 of 27”. |
select[data-dt-page-size] | Rows-per-page picker. |
mv-pagination | Controlled pagination (hidden when there is only one page, unless data-dt-always). |
.mv-data-table-bulk | Floating bulk-actions bar, shown as soon as a row is checked; [data-dt-bulk-count], [data-dt-action], [data-dt-clear]. |
CSS classes
| Name | Description |
|---|---|
mv-data-table-toolbar / -toolbar-end / -footer | Bars above and below the table. |
[data-dt-label] | Button label visually hidden in narrow containers (still the accessible name). |
mv-data-table-person / -mono | Avatar + name + email cells, monospace IDs. |
Accessibility
Sorting uses real buttons in the headers with aria-sort; checkboxes are named after their row (“Select ORD-4821”) and the header checkbox supports the indeterminate state; rows carry aria-selected; the result count is announced (role=status) after a search or filter; the actions bar is a named role=toolbar; the column menu uses menuitemcheckbox items and stays open; pagination is keyboard navigable.