Listagens e tabelas
mad-col (formatters)
mad-data-row
totais
agrupamento
mad-data-row não é uma tag autoral
O catálogo lista
mad-data-row nesta página, mas ela não existe
como tag Blade pra escrever — é o nome do partial interno que o
MadDataGrid usa pra renderizar cada <tr> (inclusive na
atualização parcial via manageRow()/removeRow()).
Não há atributo/prop pra declará-la diretamente no Blade; reportado
como limitação/imprecisão do catálogo nesta versão do framework.
Formatadores de coluna
prefix, badge, date e money — direto nos atributos do mad-col.
Visible columns
|
Código
|
Estado
|
Data
|
Valor
|
|---|---|---|---|
| 1 | Enviado | 11/03/2026 | R$ 2.358,46 |
| 2 | Cancelado | 18/03/2026 | R$ 747,15 |
| 3 | Entregue | 26/10/2025 | R$ 7.424,20 |
| 4 | Entregue | 15/12/2025 | R$ 8.578,21 |
| 5 | Em separação | 25/05/2026 | R$ 4.406,22 |
| 6 | Enviado | 04/07/2026 | R$ 2.329,41 |
| 7 | Cancelado | 19/06/2026 | R$ 4.309,89 |
| 8 | Entregue | 04/03/2026 | R$ 325,31 |
resources/views/tutor/examples/grids-formatacao/formatadores.blade.php
<mad-grid model="TutorDemoPedido" per-page="8">
<mad-columns>
<mad-col field="id" label="Código" width="100" prefix="#" sort />
<mad-col field="estado_id" label="Estado" width="130"
badge="1:info:Novo|2:warning:Em separação|3:primary:Enviado|4:success:Entregue|5:danger:Cancelado" />
<mad-col field="dt_pedido" label="Data" width="110" center date="d/m/Y" sort />
<mad-col field="valor_total" label="Valor" width="140" right money="R$" sort />
</mad-columns>
</mad-grid>
Transform customizado
Callable PHP formata o valor exibido — com e sem HTML.
Visible columns
|
Cod.
|
Descrição (truncada)
|
Cliente (via $row->__record)
|
Faixa de valor
|
Valor
|
|---|---|---|---|---|
| 1 | Pedido #1 | João Gomes (Caxias do Sul/RS) | Alto | R$ 2.358,46 |
| 2 | Pedido #2 | Mariana Almeida (Recife/PE) | Médio | R$ 747,15 |
| 3 | Pedido #3 | Vanessa Gomes (Vitória/ES) | Alto | R$ 7.424,20 |
| 4 | Pedido #4 | Otávio Gomes (Goiânia/GO) | Alto | R$ 8.578,21 |
| 5 | Pedido #5 | Fábio Souza (Uberlândia/MG) | Alto | R$ 4.406,22 |
| 6 | Pedido #6 | Carla Almeida (Rio de Janeiro/RJ) | Alto | R$ 2.329,41 |
| 7 | Pedido #7 | João Gomes (Caxias do Sul/RS) | Alto | R$ 4.309,89 |
| 8 | Pedido #8 | Mariana Almeida (Recife/PE) | Médio | R$ 325,31 |
resources/views/tutor/examples/grids-formatacao/transform.blade.php
<mad-grid model="TutorDemoPedido" per-page="8">
<mad-columns>
<mad-col field="id" label="Cod." width="70" sort />
<mad-col field="descricao" label="Descrição (truncada)"
transform="TutorGridsFormatacao::truncarDescricao" />
<mad-col field="cliente_id" label="Cliente (via $row->__record)"
transform="TutorGridsFormatacao::colClienteCidade" />
<mad-col field="valor_total" label="Faixa de valor" width="150"
transform="TutorGridsFormatacao::faixaValor" html />
<mad-col field="valor_total" label="Valor" width="130" right money="R$" />
</mad-columns>
</mad-grid>
app/control/Tutor/TutorGridsFormatacao.php
/** Transform de COLUNA com HTML (precisa do atributo `html` no <mad-col>). */
public static function faixaValor(mixed $value, object $row): string
{
$valor = (float) $value;
[$variant, $texto] = match (true) {
$valor >= 1000 => ['success', 'Alto'],
$valor >= 300 => ['warning', 'Médio'],
default => ['secondary', 'Baixo'],
};
return sprintf(
'<span class="mad-badge mad-badge-%s">%s</span>',
htmlspecialchars($variant, ENT_QUOTES),
htmlspecialchars($texto, ENT_QUOTES)
);
}
Totais no rodapé
total="sum|avg|count" agrega a coluna inteira no rodapé.
Visible columns
|
Cod.
|
Descrição
|
Valor
|
Média
|
|---|---|---|---|
| 1 | Pedido #1 | R$ 2.358,46 | R$ 2.358,46 |
| 2 | Pedido #2 | R$ 747,15 | R$ 747,15 |
| 3 | Pedido #3 | R$ 7.424,20 | R$ 7.424,20 |
| 4 | Pedido #4 | R$ 8.578,21 | R$ 8.578,21 |
| 5 | Pedido #5 | R$ 4.406,22 | R$ 4.406,22 |
| 6 | Pedido #6 | R$ 2.329,41 | R$ 2.329,41 |
| 7 | Pedido #7 | R$ 4.309,89 | R$ 4.309,89 |
| 8 | Pedido #8 | R$ 325,31 | R$ 325,31 |
| 9 | Pedido #9 | R$ 6.631,58 | R$ 6.631,58 |
| 10 | Pedido #10 | R$ 10.761,97 | R$ 10.761,97 |
| 10 | R$ 4.787,24 | R$ 4.787,24 |
resources/views/tutor/examples/grids-formatacao/totais.blade.php
<mad-grid model="TutorDemoPedido" per-page="10" sticky>
<mad-columns>
<mad-col field="id" label="Cod." width="70" total="count" />
<mad-col field="descricao" label="Descrição" />
<mad-col field="valor_total" label="Valor" width="140" right money="R$" total="sum" />
<mad-col field="valor_total" label="Média" width="130" right money="R$" total="avg" />
</mad-columns>
</mad-grid>
Agrupamento com subtotal
group-by + group-mask + group-total. O mask usa só o campo cru (categoria_id) — uma seta de relação dentro do valor do atributo quebra o parser da tag do grid (ver comentário no código-fonte do exemplo).
Visible columns
|
Cod.
|
Descrição
|
Data
|
Valor
|
|---|---|---|---|
|
Categoria 2
2
Valor:
R$ 6.668,35
|
|||
| 1 | Pedido #1 | 11/03/2026 | R$ 2.358,46 |
| 7 | Pedido #7 | 19/06/2026 | R$ 4.309,89 |
| R$ 6.668,35 | |||
|
Categoria 5
1
Valor:
R$ 747,15
|
|||
| 2 | Pedido #2 | 18/03/2026 | R$ 747,15 |
| R$ 747,15 | |||
|
Categoria 1
1
Valor:
R$ 7.424,20
|
|||
| 3 | Pedido #3 | 26/10/2025 | R$ 7.424,20 |
| R$ 7.424,20 | |||
|
Categoria 7
2
Valor:
R$ 15.209,79
|
|||
| 4 | Pedido #4 | 15/12/2025 | R$ 8.578,21 |
| 9 | Pedido #9 | 23/02/2026 | R$ 6.631,58 |
| R$ 15.209,79 | |||
|
Categoria 4
2
Valor:
R$ 4.731,53
|
|||
| 5 | Pedido #5 | 25/05/2026 | R$ 4.406,22 |
| 8 | Pedido #8 | 04/03/2026 | R$ 325,31 |
| R$ 4.731,53 | |||
|
Categoria 8
1
Valor:
R$ 2.329,41
|
|||
| 6 | Pedido #6 | 04/07/2026 | R$ 2.329,41 |
| R$ 2.329,41 | |||
|
Categoria 6
1
Valor:
R$ 10.761,97
|
|||
| 10 | Pedido #10 | 08/03/2026 | R$ 10.761,97 |
| R$ 10.761,97 | |||
| R$ 47.872,40 |
resources/views/tutor/examples/grids-formatacao/agrupamento.blade.php
@php
// group-by/group-mask/group-total só existem no modo "self" (via
// _renderInlineGrid()) — o modo zero-PHP (grid com model= direto na tag)
// NUNCA aplica agrupamento (mount()/_renderFromConfig() não copiam esses
// campos do config pra a instância). Por isso este exemplo (só ele, nesta
// página) precisa do self + do fix de $__component: o partial é
// incluído dentro do componente Blade nativo tutor-demo (escopo isolado)
// e o modo self compila pra uma chamada em cima da variável LEXICAL
// $__component, que não atravessa esse aninhamento sozinha.
// NUNCA escreva o texto literal da tag grid+self dentro de um comentário
// neste arquivo: o compilador de tags do MAD é regex-based e não entende
// comentário PHP — ele casaria a abertura aqui no comentário com o
// fechamento real lá embaixo (bug real, já pego em produção neste lote).
//
// group-mask NÃO pode ter "->" dentro do valor do atributo (ex.: um mask
// tipo "{relacao->campo}"): confirmado em tinker que o "seta" de
// ->campo tem um ">" que o regex externo da tag do grid (que só para
// no PRIMEIRO ">" que encontra) interpreta como o fechamento da própria
// tag — o atributo group-mask vira um bool solto (true) em vez de string, e
// (string) true = "1" acaba sendo o mask literal usado (grupo mostra
// "1" pra TODO mundo). Por isso o mask abaixo usa só o campo cru
// ({categoria_id}), igual ao padrao ja usado noutras telas do projeto.
$__component = \Mad\Component\MadRenderContext::getComponent();
@endphp
<mad-grid self per-page="10" sticky
group-by="categoria_id" group-mask="Categoria {categoria_id}" group-total>
<mad-columns>
<mad-col field="id" label="Cod." width="70" />
<mad-col field="descricao" label="Descrição" />
<mad-col field="dt_pedido" label="Data" width="110" date="d/m/Y" />
<mad-col field="valor_total" label="Valor" width="140" right money="R$" total="sum" />
</mad-columns>
</mad-grid>
Código-fonte completo da página
app/control/Tutor/TutorGridsFormatacao.php
<?php
namespace App\Control\Tutor;
use App\Models\TutorDemo\TutorDemoPedido;
use App\Support\Tutor\TutorDemoSeed;
use Mad\Grid\MadDataGrid;
/**
* TutorGridsFormatacao — formatadores de <mad-col> (money/date/badge), transform
* custom (com e sem HTML, com e sem relação via $row->__record), totais de
* rodapé (total="sum") e agrupamento com subtotal (group-by/group-mask/group-total).
*
* ESTENDE MadDataGrid (não TutorPage): descoberto na prática (renderização real
* via tinker, não só leitura de doc) que `<mad-grid model="...">` (modo
* zero-PHP) NUNCA aplica groupBy/groupMask/groupTotal — MadGrid::mount()/
* _renderFromConfig() só copiam model/database/perPage/actionSide/exportable/
* searchable/defaultSort do config pro componente; agrupamento só existe em
* MadDataGrid::_renderInlineGrid() (`<mad-grid self>`), que por sua vez só
* existe numa subclasse de verdade. Os outros 4 exemplos desta página (que
* não precisam de agrupamento) continuam em modo zero-PHP normalmente.
*
* Gotcha de nesting: `<mad-grid self>` compila para `$__component->
* _renderInlineGrid(...)` — variável LEXICAL, não resolvida via
* MadRenderContext. Como cada exemplo é um partial incluído dentro do
* componente Blade <x-tutor-demo> (escopo isolado — confirmado empiricamente
* com um teste descartável via tinker), $__component não sobrevive até lá.
* O fix (mesmo usado por TutorGridsFiltros): reatribuir
* `$__component = \Mad\Component\MadRenderContext::getComponent();` no TOPO
* do partial que usa <mad-grid self> — esse helper é resolvido via um stack
* estático (push/pop em MadComponent::render()), não por escopo léxico, então
* atravessa qualquer aninhamento de componentes Blade.
*/
class TutorGridsFormatacao extends MadDataGrid
{
protected static string $wrapper = self::INTERNAL;
protected string $model = TutorDemoPedido::class;
protected string $database = 'business';
protected array $with = ['cliente', 'estado'];
public function mount(array $params = []): void
{
TutorDemoSeed::ensure();
parent::mount($params);
}
// ── Transforms de coluna ──────────────────────────────────────────────
// Assinatura: (mixed $value, object $row[, array $rowArr]) — 2o arg é
// stdClass (cast do row), NUNCA array. Ver grid-datagrid.md.
/** Transform de COLUNA com HTML (precisa do atributo `html` no <mad-col>). */
public static function faixaValor(mixed $value, object $row): string
{
$valor = (float) $value;
[$variant, $texto] = match (true) {
$valor >= 1000 => ['success', 'Alto'],
$valor >= 300 => ['warning', 'Médio'],
default => ['secondary', 'Baixo'],
};
return sprintf(
'<span class="mad-badge mad-badge-%s">%s</span>',
htmlspecialchars($variant, ENT_QUOTES),
htmlspecialchars($texto, ENT_QUOTES)
);
}
/** Transform de COLUNA em texto puro (sem `html` — o retorno é escapado normalmente). */
public static function truncarDescricao(mixed $value, object $row): string
{
$texto = (string) $value;
return $texto !== '' ? mb_strimwidth($texto, 0, 24, '…') : '-';
}
/**
* Transform de coluna de RELAÇÃO — o model Eloquent não tem render('{rel->campo}')
* como o Record legado, então uma coluna calculada a partir de uma relação
* usa transform + `$row->__record` (a instância Eloquent real da linha) em
* vez de tentar ler a relação a partir do array normalizado.
*/
public static function colClienteCidade(mixed $value, object $row): string
{
$cliente = $row->__record->cliente ?? null;
return $cliente ? "{$cliente->nome} ({$cliente->cidade}/{$cliente->uf})" : '—';
}
protected function view(): string|array
{
return 'tutor.grids.formatacao';
}
}
resources/views/tutor/grids/formatacao.blade.php
<x-tutor-page page="grids_formatacao">
<mad-callout type="warning" title="mad-data-row não é uma tag autoral" icon="triangle-alert">
O catálogo lista <code>mad-data-row</code> nesta página, mas ela não existe
como tag Blade pra escrever — é o nome do partial interno que o
MadDataGrid usa pra renderizar cada <code><tr></code> (inclusive na
atualização parcial via <code>manageRow()</code>/<code>removeRow()</code>).
Não há atributo/prop pra declará-la diretamente no Blade; reportado
como limitação/imprecisão do catálogo nesta versão do framework.
</mad-callout>
<x-tutor-demo demo="tutor.examples.grids-formatacao.formatadores"
title="Formatadores de coluna" desc="prefix, badge, date e money — direto nos atributos do mad-col." />
<x-tutor-demo demo="tutor.examples.grids-formatacao.transform"
title="Transform customizado" desc="Callable PHP formata o valor exibido — com e sem HTML."
php="TutorGridsFormatacao::faixaValor" />
<x-tutor-demo demo="tutor.examples.grids-formatacao.totais"
title="Totais no rodapé" desc="total="sum|avg|count" agrega a coluna inteira no rodapé." />
<x-tutor-demo demo="tutor.examples.grids-formatacao.agrupamento"
title="Agrupamento com subtotal" desc="group-by + group-mask + group-total. O mask usa só o campo cru (categoria_id) — uma seta de relação dentro do valor do atributo quebra o parser da tag do grid (ver comentário no código-fonte do exemplo)." />
</x-tutor-page>