Loading skeleton, empty state, and error state for table components.
These three components cover the three non-data states a table can be in: loading (skeleton shimmer), empty (no rows match), and error (fetch failed).
Sub-components
| Function | Purpose |
|---|---|
table_skeleton/1 | Animated shimmer rows while data loads |
table_empty/1 | Empty state with icon, title, and CTA |
table_error/1 | Error state with retry action slot |
Usage
<%# Loading state %>
<%= if @loading do %>
<.table_skeleton rows={5} cols={4} />
<% end %>
<%# Empty state (inside a tbody) %>
<%= if @rows == [] do %>
<.table_empty title="No users found" description="Try adjusting your search filters.">
<:action>
<.button phx-click="clear_filters" variant={:outline} size={:sm}>Clear filters</.button>
</:action>
</.table_empty>
<% end %>
<%# Error state (inside a tbody) %>
<%= if @error do %>
<.table_error message="Failed to load users.">
<:action>
<.button phx-click="retry" size={:sm}>Retry</.button>
</:action>
</.table_error>
<% end %>
Summary
Functions
Renders an empty-state row suitable for use inside a <tbody>.
Renders an error-state row suitable for use inside a <tbody>.
Renders an animated shimmer table skeleton while data is loading.
Functions
Renders an empty-state row suitable for use inside a <tbody>.
The <td colspan="100"> trick spans all columns regardless of how many
columns the table has. Works as a drop-in inside any <tbody>.
Example
<.table_empty
title="No invoices found"
description="Create your first invoice to get started."
icon="file-text"
>
<:action>
<.button phx-click="new_invoice" size={:sm}>New Invoice</.button>
</:action>
</.table_empty>Attributes
title(:string) - Primary heading of the empty state. Defaults to"No results".description(:string) - Optional secondary text beneath the title. Defaults tonil.icon(:string) - Lucide icon name for the decorative icon (e.g."search","filter","inbox"). Defaults to"inbox".class(:string) - Additional CSS classes for the<tr>. Defaults tonil.
Slots
action- Optional CTA placed below the description — typically a button or link.
Renders an error-state row suitable for use inside a <tbody>.
Uses destructive colour tokens to make the error visually distinct from the
empty state. Provide a retry action slot to let users recover inline.
Example
<.table_error message="Failed to load users. Please try again.">
<:action>
<.button phx-click="retry" variant={:outline} size={:sm}>Retry</.button>
</:action>
</.table_error>Attributes
message(:string) - Error message shown in the error state. Defaults to"Failed to load data".class(:string) - Additional CSS classes for the<tr>. Defaults tonil.
Slots
action- Optional retry button or recovery action placed below the error message.
Renders an animated shimmer table skeleton while data is loading.
All cells use motion-safe:animate-pulse so users who prefer reduced motion
see static placeholder blocks instead of animation.
Example
<.table_skeleton rows={5} cols={4} />
<%# Wider skeleton with no header %>
<.table_skeleton rows={8} cols={6} show_header={false} />Attributes
rows(:integer) - Number of skeleton rows to render. Defaults to5.cols(:integer) - Number of skeleton columns to render. Defaults to4.show_header(:boolean) - Whether to render a skeleton thead with shimmer header cells. Defaults totrue.class(:string) - Additional CSS classes for the outer wrapper div. Defaults tonil.