DataTable — OutfitKit
DataTable
Listado de datos con toolbar (búsqueda, filtros, fechas), tabla principal y footer con paginación. Construido a partir de primitivos: no existe ningún componente DataTable en OutfitKit. Es composición de un Card + Searchbar / Select / Button en la toolbar + .table + Button de paginación. Consulta el ejemplo completo en examples/mini-apps/datatable.html.
Composición:
Card con header (Searchbar + Selects de filtro + Button primary), body con .table dentro de un wrapper overflow-x:auto, footer con paginación (.meta + Button ghost icon_only).
Listado · pedidos con toolbar
| Pedido | Cliente | Fecha | Total | Estado | Tipo | ||
|---|---|---|---|---|---|---|---|
| #2041 | María García | 18/10/25 14:22 | €19,40 | Pagado | POS | ||
| #2040 | Café Tuña S.L. | 18/10/25 13:48 | €142,80 | Pagado | Web | ||
| #2039 | Ana Soler | 18/10/25 12:20 | €8,40 | Procesando | App | ||
| #2038 | Bodega Pérez | 17/10/25 18:05 | €340,00 | Reembolso | POS |
<div class="card" style="width:100%">
<header class="head" style="gap:8px;flex-wrap:wrap;align-items:center">
<div class="search" style="flex:1 1 220px;max-width:300px"><iconify-icon icon="lucide:search"></iconify-icon><input class="input sm" placeholder="Buscar pedido o cliente…"/></div>
<select class="select sm"><option>Todos los estados</option><option>Pagado</option><option>Procesando</option><option>Reembolso</option></select>
<select class="select sm"><option>Todos los tipos</option><option>POS · Local</option><option>Web</option><option>App</option></select>
<span class="chip"><iconify-icon icon="lucide:calendar"></iconify-icon> 01/10/25 → 18/10/25</span>
<div style="flex:1"></div>
<button class="btn ghost sm icon" title="Importar"><iconify-icon icon="lucide:upload" width="16"></iconify-icon></button>
<button class="btn ghost sm icon" title="Exportar"><iconify-icon icon="lucide:download" width="16"></iconify-icon></button>
<button class="btn brand sm">+ Nuevo</button>
</header>
<div style="overflow-x:auto">
<table class="table">
<thead><tr><th><input type="checkbox"/></th><th>Pedido</th><th>Cliente</th><th>Fecha</th><th>Total</th><th>Estado</th><th>Tipo</th><th></th></tr></thead>
<tbody>
<tr><td><input type="checkbox"/></td><td><b>#2041</b></td><td>María García</td><td><span class="meta">18/10/25 14:22</span></td><td>€19,40</td><td><span class="chip success sm">Pagado</span></td><td><span class="chip outline sm">POS</span></td><td><button class="btn ghost sm icon"><iconify-icon icon="lucide:more-vertical" width="16"></iconify-icon></button></td></tr>
<tr><td><input type="checkbox"/></td><td><b>#2040</b></td><td>Café Tuña S.L.</td><td><span class="meta">18/10/25 13:48</span></td><td>€142,80</td><td><span class="chip success sm">Pagado</span></td><td><span class="chip outline sm">Web</span></td><td><button class="btn ghost sm icon"><iconify-icon icon="lucide:more-vertical" width="16"></iconify-icon></button></td></tr>
<tr><td><input type="checkbox"/></td><td><b>#2039</b></td><td>Ana Soler</td><td><span class="meta">18/10/25 12:20</span></td><td>€8,40</td><td><span class="chip warn sm">Procesando</span></td><td><span class="chip outline sm">App</span></td><td><button class="btn ghost sm icon"><iconify-icon icon="lucide:more-vertical" width="16"></iconify-icon></button></td></tr>
<tr><td><input type="checkbox"/></td><td><b>#2038</b></td><td>Bodega Pérez</td><td><span class="meta">17/10/25 18:05</span></td><td>€340,00</td><td><span class="chip danger sm">Reembolso</span></td><td><span class="chip outline sm">POS</span></td><td><button class="btn ghost sm icon"><iconify-icon icon="lucide:more-vertical" width="16"></iconify-icon></button></td></tr>
</tbody>
</table>
</div>
<footer class="foot row" style="justify-content:space-between">
<span class="meta">25 de 147 resultados</span>
<div class="row" style="gap:4px">
<button class="btn ghost sm icon"><iconify-icon icon="lucide:chevron-left" width="16"></iconify-icon></button>
<span class="chip brand sm">1</span><span class="chip outline sm">2</span><span class="chip outline sm">3</span>
<button class="btn ghost sm icon"><iconify-icon icon="lucide:chevron-right" width="16"></iconify-icon></button>
</div>
</footer>
</div>
<Card attrs={"data-signals": "{view: 'table'}", "style": "width:100%"}>
<!-- Toolbar -->
<header class="head" style="gap:8px;flex-wrap:wrap;align-items:center">
<Searchbar placeholder="Buscar pedido o cliente…" attrs={"style": "flex:1 1 220px;max-width:300px"} />
<Select attrs={"class": "sm"}>
<option>Todos los estados</option>
<option>Pagado</option>
<option>Procesando</option>
<option>Reembolso</option>
</Select>
<Select attrs={"class": "sm"}>
<option>Todos los tipos</option>
<option>POS · Local</option>
<option>Web</option>
<option>App</option>
</Select>
<Chip icon="lucide:calendar">01/10/25 → 18/10/25</Chip>
<div style="flex:1"></div>
<Button icon="lucide:upload" icon_only variant="ghost" size="sm" attrs={"title": "Importar"} />
<Button icon="lucide:download" icon_only variant="ghost" size="sm" attrs={"title": "Exportar"} />
<Button label="+ Nuevo" variant="brand" size="sm" />
</header>
<!-- Tabla -->
<div style="overflow-x:auto">
<table class="table">
<thead>
<tr>
<th><input type="checkbox"/></th>
<th>Pedido</th>
<th>Cliente</th>
<th>Fecha</th>
<th>Total</th>
<th>Estado</th>
<th>Tipo</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="checkbox"/></td>
<td><b>#2041</b></td>
<td>María García</td>
<td><span class="meta">18/10/25 14:22</span></td>
<td>€19,40</td>
<td><Chip color="success" size="sm">Pagado</Chip></td>
<td><Chip outline size="sm">POS</Chip></td>
<td><Button icon="lucide:more-vertical" icon_only variant="ghost" size="sm" /></td>
</tr>
<tr>
<td><input type="checkbox"/></td>
<td><b>#2040</b></td>
<td>Café Tuña S.L.</td>
<td><span class="meta">18/10/25 13:48</span></td>
<td>€142,80</td>
<td><Chip color="success" size="sm">Pagado</Chip></td>
<td><Chip outline size="sm">Web</Chip></td>
<td><Button icon="lucide:more-vertical" icon_only variant="ghost" size="sm" /></td>
</tr>
<tr>
<td><input type="checkbox"/></td>
<td><b>#2039</b></td>
<td>Ana Soler</td>
<td><span class="meta">18/10/25 12:20</span></td>
<td>€8,40</td>
<td><Chip color="warn" size="sm">Procesando</Chip></td>
<td><Chip outline size="sm">App</Chip></td>
<td><Button icon="lucide:more-vertical" icon_only variant="ghost" size="sm" /></td>
</tr>
<tr>
<td><input type="checkbox"/></td>
<td><b>#2038</b></td>
<td>Bodega Pérez</td>
<td><span class="meta">17/10/25 18:05</span></td>
<td>€340,00</td>
<td><Chip color="danger" size="sm">Reembolso</Chip></td>
<td><Chip outline size="sm">POS</Chip></td>
<td><Button icon="lucide:more-vertical" icon_only variant="ghost" size="sm" /></td>
</tr>
</tbody>
</table>
</div>
<!-- Footer paginación -->
<footer class="foot row" style="justify-content:space-between">
<span class="meta">25 de 147 resultados</span>
<div class="row" style="gap:4px">
<Button icon="lucide:chevron-left" icon_only variant="ghost" size="sm" />
<Chip color="brand" size="sm">1</Chip>
<Chip outline size="sm">2</Chip>
<Chip outline size="sm">3</Chip>
<Button icon="lucide:chevron-right" icon_only variant="ghost" size="sm" />
</div>
</footer>
</Card>
<Card attrs={"data-signals": "{view: 'table'}", "style": "width:100%"}>
<!-- Toolbar -->
<header class="head" style="gap:8px;flex-wrap:wrap;align-items:center">
<Searchbar placeholder="Buscar pedido o cliente…" attrs={"style": "flex:1 1 220px;max-width:300px"} />
<Select attrs={"class": "sm"}>
<option>Todos los estados</option>
<option>Pagado</option>
<option>Procesando</option>
<option>Reembolso</option>
</Select>
<Select attrs={"class": "sm"}>
<option>Todos los tipos</option>
<option>POS · Local</option>
<option>Web</option>
<option>App</option>
</Select>
<Chip icon="lucide:calendar">01/10/25 → 18/10/25</Chip>
<div style="flex:1"></div>
<Button icon="lucide:upload" icon_only variant="ghost" size="sm" attrs={"title": "Importar"} />
<Button icon="lucide:download" icon_only variant="ghost" size="sm" attrs={"title": "Exportar"} />
<Button label="+ Nuevo" variant="brand" size="sm" />
</header>
<!-- Tabla -->
<div style="overflow-x:auto">
<table class="table">
<thead>
<tr>
<th><input type="checkbox"/></th>
<th>Pedido</th>
<th>Cliente</th>
<th>Fecha</th>
<th>Total</th>
<th>Estado</th>
<th>Tipo</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="checkbox"/></td>
<td><b>#2041</b></td>
<td>María García</td>
<td><span class="meta">18/10/25 14:22</span></td>
<td>€19,40</td>
<td><Chip color="success" size="sm">Pagado</Chip></td>
<td><Chip outline size="sm">POS</Chip></td>
<td><Button icon="lucide:more-vertical" icon_only variant="ghost" size="sm" /></td>
</tr>
<tr>
<td><input type="checkbox"/></td>
<td><b>#2040</b></td>
<td>Café Tuña S.L.</td>
<td><span class="meta">18/10/25 13:48</span></td>
<td>€142,80</td>
<td><Chip color="success" size="sm">Pagado</Chip></td>
<td><Chip outline size="sm">Web</Chip></td>
<td><Button icon="lucide:more-vertical" icon_only variant="ghost" size="sm" /></td>
</tr>
<tr>
<td><input type="checkbox"/></td>
<td><b>#2039</b></td>
<td>Ana Soler</td>
<td><span class="meta">18/10/25 12:20</span></td>
<td>€8,40</td>
<td><Chip color="warn" size="sm">Procesando</Chip></td>
<td><Chip outline size="sm">App</Chip></td>
<td><Button icon="lucide:more-vertical" icon_only variant="ghost" size="sm" /></td>
</tr>
<tr>
<td><input type="checkbox"/></td>
<td><b>#2038</b></td>
<td>Bodega Pérez</td>
<td><span class="meta">17/10/25 18:05</span></td>
<td>€340,00</td>
<td><Chip color="danger" size="sm">Reembolso</Chip></td>
<td><Chip outline size="sm">POS</Chip></td>
<td><Button icon="lucide:more-vertical" icon_only variant="ghost" size="sm" /></td>
</tr>
</tbody>
</table>
</div>
<!-- Footer paginación -->
<footer class="foot row" style="justify-content:space-between">
<span class="meta">25 de 147 resultados</span>
<div class="row" style="gap:4px">
<Button icon="lucide:chevron-left" icon_only variant="ghost" size="sm" />
<Chip color="brand" size="sm">1</Chip>
<Chip outline size="sm">2</Chip>
<Chip outline size="sm">3</Chip>
<Button icon="lucide:chevron-right" icon_only variant="ghost" size="sm" />
</div>
</footer>
</Card>
Install the Jinja addon and import the component:
pip install outfitkit
Then in your template:
{% from "<component>.jinja" import <component> %}
{{ <component>(...) }}
Or with JinjaX:
<Component ... />