A card grid is free-form — each row can contain whatever layout you like. A table is not: it has columns, a header row, and every row needs to line up under the same headings. That structural difference is exactly why the engine gives it a separate element, dynamiclisttable, rather than making you fake a table out of a styled dynamiclist.

1 The XML

Same Contacts table, same tenant scoping, this time with a department column added to make the tabular shape worth showing:

emxml_blkContactsTable.xml
<block>

    <table type="dynamiclisttable" class="contacts-table">

        <tr type="headrow">
            <th>Name</th>
            <th>Department</th>
            <th>Email</th>
            <th class="num">Open Orders</th>
        </tr>

        <tr type="row">
            <td class="name">%contact_name%</td>
            <td><span class="dept-pill">%department%</span></td>
            <td>%email%</td>
            <td class="num">%open_order_count%</td>
        </tr>

        <!-- one query, after the row template — same rule as dynamiclist -->
        <sql>
            <query name="contacts_table"><![CDATA[
                SELECT c.contact_id, c.contact_name, c.department, c.email,
                       COUNT(o.order_id) AS open_order_count
                FROM   contacts c
                LEFT JOIN orders o ON o.contact_id = c.contact_id AND o.status = 'open'
                WHERE  c.dept_id = '%deptid%'
                GROUP BY c.contact_id
                ORDER BY c.contact_name ASC
            ]]></query>
        </sql>

    </table>

</block>

What's different from a dynamiclist

<block> wrapper
Same rule as post 3's list — the file's root is <block>, with the table nested one level in as its child, not as the root itself.
a real <table>
The marker goes on an actual <table> tag: <table type="dynamiclisttable">. Writing a bare <dynamiclisttable> instead is accepted without complaint but drops the <table> element from the output entirely, which quietly breaks every table style on the page. Always write the real tag.
<tr type="headrow">
Renders once, as the <thead> row. A dynamiclist has no equivalent — a card grid has no column headings to keep aligned.
<tr type="row">
The per-row <tbody> template — the same repeat-per-result-row idea as the list's own type="row", just constrained to <td> cells that line up under the header.
<thead> / <tbody>
You write the <table> and the two <tr> templates; the engine supplies the <thead> and <tbody> around them. Don't open or close those by hand — the whole table has to come from this one element.
one query only
Same rule as dynamiclist: exactly one <query> per element. Need data from more than one table? JOIN it into that single query, the way open_order_count is joined in above, rather than adding a second query.
2 Generated HTML
Generated HTML
<table class="contacts-table">
    <thead>
        <tr>
            <th>Name</th><th>Department</th><th>Email</th><th class="num">Open Orders</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td class="name">Sarah Whitfield</td>
            <td><span class="dept-pill">Operations</span></td>
            <td>s.whitfield@example.com</td>
            <td class="num">3</td>
        </tr>
        <!-- repeated once per row -->
    </tbody>
</table>
3 Rendered live
app.example.com/manager/contacts?view=table
NameDepartmentEmailOpen Orders
Sarah WhitfieldOperationss.whitfield@example.com3
David OkonkwoProcurementd.okonkwo@example.com7
Maria SantosFinancem.santos@example.com0
James CooperWarehousej.cooper@example.com2
The open_order_count column comes from a JOIN and a COUNT in the same single query — not a second round trip, not a per-row lookup. One query, every column.

When to reach for which

Neither component is "better" — dynamiclisttable is purpose-built for column-based data: it generates the header row and keeps every column aligned underneath it automatically. dynamiclist is the more versatile of the two, capable of far more than card-style rows — including composing with dynamiclisttable in ways worth their own dedicated look. Post 3's grid and this post's table are rendering the same underlying contacts — dynamiclisttable just meant not having to hand-build the header row and column alignment ourselves.