Início Boas práticas Tema Idiomas e RTL App e cabeçalho Layout Tipografia Abas Menu e âncora Dropdown e popover Command e toggles Botão Campos Seleção e valores Combobox e menções Datas e calendário Árvore e cascata Transfer Upload Filtros Tabela Planilha KPI e estatística Badge e tag Listas e detalhes Gráficos Imagem e carrossel Ícones Diagramas Alertas e estados Progresso e passos Diálogo e toast Drawer e notificação Utilitários Overview Work queue Report Report com htmx Form / request Tabela administrativa Página de detalhe Formulário em diálogo Gráfico com dados do servidor Buscar… llms.txt Tema Tema Restaurar Copiar prompt Copiar snippet Prompt: para as instruções de um agente. Snippet: direto no templates/base.html. v0.11.0 Data table fed with columns and rows; values are always rendered as text. Tabela com dados do Pythoncolumns + rows por JavaScript. Valores viram texto (sem XSS), formatados por type. <ab-table id="t1" heading="Faturas" exportable clickable client-sort></ab-table> <script type="module"> const t = document.getElementById("t1"); t.columns = [ { key: "cliente", label: "Cliente", sortable: true }, { key: "vencimento", label: "Vencimento", type: "date", sortable: true }, { key: "valor", label: "Valor", type: "currency", sortable: true }, { key: "status", label: "Status", type: "badge", tones: { Pago: "ok", Pendente: "warn", Atrasado: "danger" } }, ]; t.rowActions = [{ id: "edit", label: "Editar", icon: "pencil-simple" }, { id: "delete", label: "Excluir", icon: "trash", tone: "danger" }]; t.loading = true; setTimeout(() => { t.rows = [ { id: 1, cliente: "Padaria Pão Dourado", vencimento: "2026-11-03", valor: 1890.4, status: "Pago" }, { id: 2, cliente: "Oficina Rota 66", vencimento: "2026-11-10", valor: 420, status: "Pendente" }, { id: 3, cliente: "Clínica Bem Viver", vencimento: "2026-10-28", valor: 12500, status: "Atrasado" }, { id: 4, cliente: "<img src=x onerror=alert(1)>", vencimento: null, valor: null, status: "Pendente" }, ]; t.loading = false; }, 800); t.addEventListener("ab-row-click", (e) => abToast(`Abrir ${e.detail.row.cliente}`, { tone: "info" })); t.addEventListener("ab-row-action", async (e) => { if (e.detail.action === "delete" && await abConfirm({ title: "Excluir fatura?", message: e.detail.row.cliente, tone: "danger", confirmLabel: "Excluir" })) { t.rows = t.rows.filter((r) => r !== e.detail.row); abToast("Fatura excluída"); } }); </script> Ação em destaquevariant aceita primary, secondary, ghost (padrão) ou danger, como ab-button. primary usa a cor de destaque do tema. Trocar rows preserva as ações; em um novo fragmento HTML, inclua row-actions novamente, como no exemplo em JSON abaixo. Atualizar linhas <ab-table id="t-actions" heading="Pedidos de demonstração" columns='[{"key":"pedido","label":"Pedido"},{"key":"status","label":"Status"}]' rows='[{"pedido":"#1001","status":"Pendente"}]' row-actions='[{"id":"open","label":"Abrir","variant":"primary"},{"id":"details","label":"Detalhes"}]'> <ab-button slot="toolbar" id="reload-actions" icon="arrows-clockwise">Atualizar linhas</ab-button> </ab-table> <script type="module"> const t = document.getElementById("t-actions"); let pedido = 1001; document.getElementById("reload-actions").addEventListener("click", () => { t.rows = [{ pedido: `#${++pedido}`, status: "Pendente" }]; }); t.addEventListener("ab-row-action", (e) => abToast(`${e.detail.action === "open" ? "Abrir" : "Detalhes"}: ${e.detail.row.pedido}`)); </script> Paginação no servidorDefina total (de count()) e responda a ab-page-change buscando a página. <ab-table id="t2" page-size="5" page-sizes="5,10,25"></ab-table> <script type="module"> const t = document.getElementById("t2"); const all = Array.from({ length: 23 }, (_, i) => ({ pedido: `#${1000 + i}`, itens: (i * 7) % 13 + 1, total: 99.9 * (i + 1) })); t.columns = [{ key: "pedido", label: "Pedido" }, { key: "itens", label: "Itens", type: "number" }, { key: "total", label: "Total", type: "currency" }]; async function load(page, size) { t.loading = true; await new Promise((r) => setTimeout(r, 300)); // await get_orders(page, size) t.rows = all.slice((page - 1) * size, page * size); t.total = all.length; t.loading = false; } t.addEventListener("ab-page-change", (e) => load(e.detail.page, e.detail.pageSize)); load(1, 5); </script> Vazio e erro <ab-grid cols="2"> <ab-table id="t3" empty-text="Nenhuma fatura neste período"></ab-table> <ab-table id="t4"></ab-table> </ab-grid> <script type="module"> const cols = [{ key: "a", label: "Cliente" }, { key: "b", label: "Valor", type: "currency" }]; Object.assign(document.getElementById("t3"), { columns: cols, rows: [] }); const t4 = document.getElementById("t4"); Object.assign(t4, { columns: cols, rows: [], error: "Não foi possível carregar as faturas." }); t4.addEventListener("ab-retry", () => { t4.error = ""; t4.rows = [{ a: "Recarregado", b: 10 }]; }); </script> Texto com Markdowntype: "markdown" renderiza código inline, negrito, itálico e links da célula como elementos (nunca como HTML; só links http(s), mailto e relativos). Útil para descrições e documentação. <ab-table id="t-md" heading="Atributos"></ab-table> <script type="module"> const t = document.getElementById("t-md"); t.columns = [ { key: "name", label: "Nome", type: "markdown", width: "10rem" }, { key: "description", label: "Descrição", type: "markdown" }, ]; t.rows = [ { name: "`value`", description: "Chave do item selecionado. Veja **ab-select**." }, { name: "`href`", description: "Transforma o item em link; detalhes no [guia](/guide/)." }, ]; </script> Paginação sozinhaab-pagination é a mesma paginação da tabela, para listas e cards. Informe total, page e page-size; ab-page-change traz a página pedida para buscar no servidor. <ab-pagination id="pag-solo" total="248" page="3" page-size="25" page-sizes="25,50,100"></ab-pagination> <script type="module"> const pag = document.getElementById("pag-solo"); pag.addEventListener("ab-page-change", (e) => { pag.page = e.detail.page; pag.pageSize = e.detail.pageSize; }); </script> APIAtributos, propriedades, métodos, eventos e slots de cada tag. <ab-table>

Data table fed with columns and rows; values are always rendered as text. Built-in loading, empty and error states; sorting; row click; row actions; pagination; CSV export.

Data flow: set rows (and total when paginating on the server) every time new data arrives; the table re-renders from scratch, so updating many times or replacing with [] is safe. Setting properties before the component has loaded is safe too. null / undefined cells render empty. Pages are 1-based. Server-side tables keep page, page size, sort and filters in one state object, reload on ab-page-change / ab-sort-change / ab-filter-change, and load with abLoad(table, () => get_rows(state)) (loading, error, retry and stale responses handled; a Python function may return { rows, total }).

<ab-pagination>Server-side pagination: "Página x de y", previous/next and optional page size.