Packages

shadcn/ui-inspired component library for Phoenix LiveView with eject-based distribution. CSS-first theme system, 829 components across 20+ categories — Calendar, Chart, Animation, DnD, Editor, Collaboration, Typography, Navigation, Background, Surface, and more.

Current section

Files

Jump to
phia_ui priv templates components table.ex.eex
Raw

priv/templates/components/table.ex.eex

defmodule <%= @module_name %>.Components.UI.Table do
@moduledoc """
Composable Table component for dense data grids in dashboards.
Ejected from PhiaUI — owns this copy of the source. Customise freely.
> #### LiveView Streams compatibility {: .tip}
>
> Use table_body/1 as the stream container:
>
> <.table_body id="users" phx-update="stream">
> <.table_row :for={{dom_id, user} <- @streams.users} id={dom_id}>
> <.table_cell><%%= user.name %></.table_cell>
> </.table_row>
> </.table_body>
## Example
<.table>
<.table_caption>Users</.table_caption>
<.table_header>
<.table_row>
<.table_head>Name</.table_head>
<.table_head>Email</.table_head>
</.table_row>
</.table_header>
<.table_body>
<.table_row>
<.table_cell>Alice</.table_cell>
<.table_cell>alice@example.com</.table_cell>
</.table_row>
</.table_body>
</.table>
"""
use Phoenix.Component
import <%= @module_name %>.ClassMerger, only: [cn: 1]
attr :class, :string, default: nil, doc: "Additional CSS classes for outer wrapper"
attr :rest, :global, doc: "HTML attributes forwarded to the outer div"
slot :inner_block, required: true
def table(assigns) do
~H"""
<div class={cn(["relative w-full overflow-auto", @class])} {@rest}>
<table class="w-full caption-bottom text-sm">
<%%= render_slot(@inner_block) %>
</table>
</div>
"""
end
attr :class, :string, default: nil, doc: "Additional CSS classes"
attr :rest, :global
slot :inner_block, required: true
def table_header(assigns) do
~H"""
<thead class={cn(["[&_tr]:border-b", @class])} {@rest}>
<%%= render_slot(@inner_block) %>
</thead>
"""
end
attr :class, :string, default: nil, doc: "Additional CSS classes"
attr :rest, :global, doc: "Supports phx-update for LiveView Streams"
slot :inner_block, required: true
def table_body(assigns) do
~H"""
<tbody class={cn(["[&_tr:last-child]:border-0", @class])} {@rest}>
<%%= render_slot(@inner_block) %>
</tbody>
"""
end
attr :class, :string, default: nil, doc: "Additional CSS classes"
attr :rest, :global
slot :inner_block, required: true
def table_footer(assigns) do
~H"""
<tfoot class={cn(["border-t bg-muted/50 font-medium", @class])} {@rest}>
<%%= render_slot(@inner_block) %>
</tfoot>
"""
end
attr :class, :string, default: nil, doc: "Additional CSS classes"
attr :selected, :boolean, default: false, doc: "Marks row as selected"
attr :rest, :global
slot :inner_block, required: true
def table_row(assigns) do
~H"""
<tr
class={cn(["border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted", @class])}
data-state={@selected && "selected"}
{@rest}
>
<%%= render_slot(@inner_block) %>
</tr>
"""
end
attr :class, :string, default: nil, doc: "Additional CSS classes"
attr :rest, :global
slot :inner_block, required: true
def table_head(assigns) do
~H"""
<th class={cn(["h-10 px-2 text-left align-middle font-medium text-muted-foreground", @class])} {@rest}>
<%%= render_slot(@inner_block) %>
</th>
"""
end
attr :class, :string, default: nil, doc: "Additional CSS classes"
attr :rest, :global
slot :inner_block, required: true
def table_cell(assigns) do
~H"""
<td class={cn(["p-2 align-middle", @class])} {@rest}>
<%%= render_slot(@inner_block) %>
</td>
"""
end
attr :class, :string, default: nil, doc: "Additional CSS classes"
attr :rest, :global
slot :inner_block, required: true
def table_caption(assigns) do
~H"""
<caption class={cn(["mt-4 text-sm text-muted-foreground", @class])} {@rest}>
<%%= render_slot(@inner_block) %>
</caption>
"""
end
end