Files
Rivertalk/lib/river_connect_web/components/ui/table.ex
T
2026-02-12 17:10:03 -06:00

210 lines
5.0 KiB
Elixir

defmodule RiverConnectWeb.Components.UI.Table do
@moduledoc """
Implementation of table components from https://ui.shadcn.com/docs/components/table
with proper ARIA attributes for accessibility.
## Examples:
<.table aria-label="Invoices">
<.table_caption>A list of your recent invoices.</.table_caption>
<.table_header>
<.table_row>
<.table_head class="w-[100px]">Invoice</.table_head>
<.table_head>Status</.table_head>
<.table_head>Method</.table_head>
<.table_head class="text-right">Amount</.table_head>
</.table_row>
</.table_header>
<.table_body>
<.table_row :for={invoice <- @invoices}>
<.table_cell class="font-medium"><%= invoice.number %></.table_cell>
<.table_cell><%= invoice.status %></.table_cell>
<.table_cell><%= invoice.method %></.table_cell>
<.table_cell class="text-right"><%= invoice.amount %></.table_cell>
</.table_row>
</.table_body>
</.table>
"""
use RiverConnectWeb.Components.UI, :component
@doc """
Renders a data table.
## Attributes
* `:class` - Additional CSS classes for the table
* `:aria-label` - Accessible name for the table when no caption is present
* `:aria-describedby` - ID of an element that describes the table
"""
attr :class, :string, default: nil
attr :"aria-label", :string, default: nil
attr :"aria-describedby", :string, default: nil
attr :rest, :global
slot :inner_block, required: true
def table(assigns) do
~H"""
<table
class={classes(["w-full caption-bottom text-sm", @class])}
aria-label={assigns[:"aria-label"]}
aria-describedby={assigns[:"aria-describedby"]}
{@rest}
>
{render_slot(@inner_block)}
</table>
"""
end
@doc """
Renders the table header container.
"""
attr :class, :string, default: nil
attr :rest, :global
slot :inner_block, required: true
def table_header(assigns) do
~H"""
<thead class={classes(["[&_tr]:border-b", @class])} {@rest}>
{render_slot(@inner_block)}
</thead>
"""
end
@doc """
Renders a table row.
## Attributes
* `:class` - Additional CSS classes
* `:aria-rowindex` - Numeric index of the row
"""
attr :class, :string, default: nil
attr :"aria-rowindex", :integer, default: nil
attr :rest, :global
slot :inner_block, required: true
def table_row(assigns) do
~H"""
<tr
class={
classes([
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
@class
])
}
aria-rowindex={assigns[:"aria-rowindex"]}
{@rest}
>
{render_slot(@inner_block)}
</tr>
"""
end
@doc """
Renders a table column header.
## Attributes
* `:class` - Additional CSS classes
* `:scope` - Scope of the header cell (default: "col")
* `:aria-sort` - Sort direction for screen readers (ascending, descending, or none)
"""
attr :class, :string, default: nil
attr :scope, :string, default: "col"
attr :"aria-sort", :string, default: nil
attr :rest, :global
slot :inner_block, required: true
def table_head(assigns) do
~H"""
<th
class={
classes([
"h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
@class
])
}
scope={@scope}
aria-sort={assigns[:"aria-sort"]}
{@rest}
>
{render_slot(@inner_block)}
</th>
"""
end
@doc """
Renders the table body.
"""
attr :class, :string, default: nil
attr :rest, :global
slot :inner_block, required: true
def table_body(assigns) do
~H"""
<tbody class={classes(["[&_tr:last-child]:border-0", @class])} {@rest}>
{render_slot(@inner_block)}
</tbody>
"""
end
@doc """
Renders a table data cell.
## Attributes
* `:class` - Additional CSS classes
"""
attr :class, :any, default: nil
attr :rest, :global
slot :inner_block, required: true
def table_cell(assigns) do
~H"""
<td class={classes(["p-4 align-middle [&:has([role=checkbox])]:pr-0", @class])} {@rest}>
{render_slot(@inner_block)}
</td>
"""
end
@doc """
Renders a table footer.
"""
attr :class, :string, default: nil
attr :rest, :global, include: ~w(disabled form name value)
slot :inner_block, required: true
def table_footer(assigns) do
~H"""
<tfoot
class={
classes([
"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
@class
])
}
{@rest}
>
{render_slot(@inner_block)}
</tfoot>
"""
end
@doc """
Renders a table caption.
A caption provides an accessible name for the table.
"""
attr :class, :string, default: nil
attr :rest, :global
slot :inner_block, required: true
def table_caption(assigns) do
~H"""
<caption class={classes(["mt-4 text-sm text-muted-foreground", @class])} {@rest}>
{render_slot(@inner_block)}
</caption>
"""
end
end