Table

A structured grid element that organizes data into rows and columns, supporting headers, captions, and footers.

Loading...
{%- set invoices = [
    {invoice: 'INV001', paymentStatus: 'Paid', totalAmount: '$250.00', paymentMethod: 'Credit Card'},
    {invoice: 'INV002', paymentStatus: 'Pending', totalAmount: '$150.00', paymentMethod: 'PayPal'},
    {invoice: 'INV003', paymentStatus: 'Unpaid', totalAmount: '$350.00', paymentMethod: 'Bank Transfer'},
    {invoice: 'INV004', paymentStatus: 'Paid', totalAmount: '$450.00', paymentMethod: 'Credit Card'},
    {invoice: 'INV005', paymentStatus: 'Paid', totalAmount: '$550.00', paymentMethod: 'PayPal'},
    {invoice: 'INV006', paymentStatus: 'Pending', totalAmount: '$200.00', paymentMethod: 'Bank Transfer'},
    {invoice: 'INV007', paymentStatus: 'Unpaid', totalAmount: '$300.00', paymentMethod: 'Credit Card'},
] -%}
<twig:Table>
    <twig:Table:Caption>A list of your recent invoices.</twig:Table:Caption>
    <twig:Table:Header>
        <twig:Table:Row>
            <twig:Table:Head class="w-[100px]">Invoice</twig:Table:Head>
            <twig:Table:Head>Status</twig:Table:Head>
            <twig:Table:Head>Method</twig:Table:Head>
            <twig:Table:Head class="text-right">Amount</twig:Table:Head>
        </twig:Table:Row>
    </twig:Table:Header>
    <twig:Table:Body>
        {% for invoice in invoices %}
            <twig:Table:Row>
                <twig:Table:Cell class="font-medium">{{ invoice.invoice }}</twig:Table:Cell>
                <twig:Table:Cell>{{ invoice.paymentStatus }}</twig:Table:Cell>
                <twig:Table:Cell>{{ invoice.paymentMethod }}</twig:Table:Cell>
                <twig:Table:Cell class="text-right">{{ invoice.totalAmount }}</twig:Table:Cell>
            </twig:Table:Row>
        {% endfor %}
    </twig:Table:Body>
    <twig:Table:Footer>
        <twig:Table:Row>
            <twig:Table:Cell colspan="3">Total</twig:Table:Cell>
            <twig:Table:Cell class="text-right">$1,500.00</twig:Table:Cell>
        </twig:Table:Row>
    </twig:Table:Footer>
</twig:Table>

Installation

bin/console ux:install table --kit shadcn

That's it!

Install the following Composer dependencies:

composer require tales-from-a-dev/twig-tailwind-extra:^1.0.0

Copy the following file(s) into your Symfony app:

{# @block content The default block #}
<div class="relative w-full overflow-auto" data-slot="table-container">
    <table
        class="{{ 'w-full caption-bottom text-sm ' ~ attributes.render('class')|tailwind_merge }}"
        {{ attributes }}
    >
        {%- block content %}{% endblock -%}
    </table>
</div>
{# @block content The default block #}
<tbody
    class="{{ '[&_tr:last-child]:border-0 ' ~ attributes.render('class')|tailwind_merge }}"
    data-slot="table-body"
    {{ attributes }}
>
    {%- block content %}{% endblock -%}
</tbody>
{# @block content The default block #}
<caption
    class="{{ 'text-muted-foreground mt-4 text-sm ' ~ attributes.render('class')|tailwind_merge }}"
    data-slot="table-caption"
    {{ attributes }}
>
    {%- block content %}{% endblock -%}
</caption>
{# @block content The default block #}
<td
    class="{{ 'p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px] ' ~ attributes.render('class')|tailwind_merge }}"
    data-slot="table-cell"
    {{ attributes }}
>
    {%- block content %}{% endblock -%}
</td>
{# @block content The default block #}
<tfoot
    class="{{ 'border-t bg-muted/50 font-medium [&>tr]:last:border-b-0 ' ~ attributes.render('class')|tailwind_merge }}"
    data-slot="table-footer"
    {{ attributes }}
>
    {%- block content %}{% endblock -%}
</tfoot>
{# @block content The default block #}
<th
    class="{{ 'text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px] ' ~ attributes.render('class')|tailwind_merge }}"
    data-slot="table-head"
    {{ attributes }}
>
    {%- block content %}{% endblock -%}
</th>
{# @block content The default block #}
<thead
    class="{{ '[&_tr]:border-b ' ~ attributes.render('class')|tailwind_merge }}"
    data-slot="table-header"
    {{ attributes }}
>
    {%- block content %}{% endblock -%}
</thead>
{# @block content The default block #}
<tr
    class="{{ 'hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors ' ~ attributes.render('class')|tailwind_merge }}"
    data-slot="table-row"
    {{ attributes }}
>
    {%- block content %}{% endblock -%}
</tr>

Happy coding!

Usage

<twig:Table>
    <twig:Table:Caption>A list of your recent invoices.</twig:Table:Caption>
    <twig:Table:Header>
        <twig:Table:Row>
            <twig:Table:Head class="w-[100px]">Invoice</twig:Table:Head>
            <twig:Table:Head>Status</twig:Table:Head>
            <twig:Table:Head>Method</twig:Table:Head>
            <twig:Table:Head class="text-right">Amount</twig:Table:Head>
        </twig:Table:Row>
    </twig:Table:Header>
    <twig:Table:Body>
        <twig:Table:Row>
            <twig:Table:Cell class="font-medium">INV001</twig:Table:Cell>
            <twig:Table:Cell>Paid</twig:Table:Cell>
            <twig:Table:Cell>Credit Card</twig:Table:Cell>
            <twig:Table:Cell class="text-right">$250.00</twig:Table:Cell>
        </twig:Table:Row>
    </twig:Table:Body>
</twig:Table>

API Reference

Table

Block Description
content The default block

Table:Body

Block Description
content The default block

Table:Caption

Block Description
content The default block

Table:Cell

Block Description
content The default block

Table:Footer

Block Description
content The default block

Table:Head

Block Description
content The default block

Table:Header

Block Description
content The default block

Table:Row

Block Description
content The default block