How It Works
Desktop (>1024px)
- Standard table layout with columns
- Headers visible at top
- Data in rows and columns
- Full table width displayed
Tablet (769px - 1024px)
- Table becomes horizontally scrollable
- Maintains desktop structure
- Prevents cramped columns
- Smooth scrolling on touch devices
Mobile (≤768px)
- Each row becomes a card
- Headers hidden
- Labels from
data-label - Label: Value pattern
- Stacked vertically
Try it:
Resize your browser window to see the responsive behavior:- 1024px → 769px: Table becomes scrollable (prevents cramping)
- 768px and below: Transforms into stacked cards
Basic Responsive Table
Simple user data table with automatic mobile transformation
| ID | Name | Role | Status | |
|---|---|---|---|---|
| #1001 | John Doe | john.doe@example.com | Admin | Active |
| #1002 | Jane Smith | jane.smith@example.com | Editor | Pending |
| #1003 | Bob Johnson | bob.johnson@example.com | Viewer | Active |
| #1004 | Alice Williams | alice.w@example.com | Editor | Inactive |
Product Catalog
E-commerce product table with prices and stock status
| Product | Category | Price | Stock | Rating | |
|---|---|---|---|---|---|
|
|
MacBook Pro 16" | Laptops | $2,499.00 | In Stock | ⭐⭐⭐⭐⭐ (4.8) |
|
|
iPhone 15 Pro | Smartphones | $999.00 | Low Stock | ⭐⭐⭐⭐⭐ (4.9) |
|
|
AirPods Pro (2nd gen) | Audio | $249.00 | In Stock | ⭐⭐⭐⭐⭐ (4.6) |
|
|
iPad Air M2 | Tablets | $599.00 | Out of Stock | ⭐⭐⭐⭐⭐ (4.7) |
Recent Orders
Order management table with dates, customers, and amounts
| Order # | Date | Customer | Items | Total | Status | |
|---|---|---|---|---|---|---|
|
|
#ORD-2501 | Oct 23, 2025 | Sarah Connor | 3 items | $3,247.00 | Delivered |
|
|
#ORD-2502 | Oct 22, 2025 | John Matrix | 1 item | $999.00 | Shipped |
|
|
#ORD-2503 | Oct 21, 2025 | Ellen Ripley | 5 items | $1,847.00 | Processing |
|
|
#ORD-2504 | Oct 20, 2025 | Martin Riggs | 2 items | $548.00 | Cancelled |
CSS Grid Custom Layouts
Use .pa-table--responsive-grid for custom multi-column mobile layouts
| Actions | First Name | Last Name | Phone | Department | Status | |
|---|---|---|---|---|---|---|
|
|
Sarah | Johnson | sarah.johnson@company.com | +1 (555) 123-4567 | Engineering | Active |
|
|
Michael | Chen | michael.chen@company.com | +1 (555) 234-5678 | Marketing | Pending |
|
|
Emma | Rodriguez | emma.rodriguez@company.com | +1 (555) 345-6789 | Sales | Active |
HTML Implementation
How to make your tables responsive
1. Add the class modifier
Add .pa-table--responsive to your table element:
html
<table class="pa-table pa-table--responsive">
<!-- table content -->
</table>
2. Add data-label attributes
Each <td> needs a data-label attribute matching its column header:
html
<table class="pa-table pa-table--responsive">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="Name">John Doe</td>
<td data-label="Email">john@example.com</td>
<td data-label="Status">
<span class="pa-badge pa-badge--success">Active</span>
</td>
</tr>
</tbody>
</table>
3. That's it!
The table will automatically transform on screens smaller than 768px. No JavaScript required!
Pro tip:
Combine with.pa-table--striped for better readability on desktop. The striping is automatically disabled on mobile.
CSS Grid Layout (Advanced)
For more control over mobile layouts, use .pa-table--responsive-grid instead:
html
<table class="pa-table pa-table--responsive-grid">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Phone</th>
</tr>
</thead>
<tbody>
<tr data-grid="2">
<td data-label="First Name">John</td>
<td data-label="Last Name">Doe</td>
<td data-label="Email" data-span="full">john@example.com</td>
<td data-label="Phone">555-1234</td>
</tr>
</tbody>
</table>
Grid Attributes:
| Attribute | Description | Example |
|---|---|---|
data-grid="2"
| 2-column grid on mobile (applies to <tr>) | Name fields side-by-side |
data-grid="3"
| 3-column grid on mobile (applies to <tr>) | Compact data display |
data-span="2"
| Span 2 columns (applies to <td>) | Wider fields |
data-span="3"
| Span 3 columns (applies to <td>) | Extra wide fields |
data-span="full"
| Span all columns (applies to <td>) | Email, description, status |
Grid vs Simple:
Use--responsive-grid when you need custom layouts. Use plain --responsive for simple label:value stacking.
Customization Variables
SCSS variables for responsive table styling
| Variable | Default Value | Description |
|---|---|---|
$table-responsive-breakpoint
|
768px
| Screen width where tables switch to stacked layout |
$table-responsive-card-margin
|
1rem
| Space between stacked row cards |
$table-responsive-card-padding
|
0.75rem
| Inner padding for each card cell |
$table-responsive-label-width
|
40%
| Width allocated for labels in mobile view |
$table-responsive-label-font-weight
|
$font-weight-semibold
| Font weight for labels (default: 600) |
Customize in your theme:
Override these variables in your theme file to adjust the responsive behavior and styling.Testing Tips
Desktop Browser
- Resize browser window
- Use DevTools device toolbar
- Press F12 → Toggle device toolbar
Real Device
- Test on actual phones/tablets
- Check both orientations
- Verify touch interactions
Common Breakpoints
- Mobile: 320px - 767px
- Tablet: 768px - 1023px
- Desktop: 1024px+
LiveView Component Code Examples
Using Table Component
heex
<.table rows={@users} is_responsive is_striped>
<:col :let={row} label="Name">{row.name}</:col>
<:col :let={row} label="Email">{row.email}</:col>
<:col :let={row} label="Status">
<.badge variant="success">{row.status}</.badge>
</:col>
</.table>
Inside a Card
heex
<.card title_text="Users" has_padding={false}>
<.table rows={@users} is_responsive>
<:col :let={row} label="Name">{row.name}</:col>
<:col :let={row} label="Email">{row.email}</:col>
<:col :let={row} label="Status">
<.badge variant="success">{row.status}</.badge>
</:col>
</.table>
</.card>
Key Points
heex
<%!-- The is_responsive attribute handles data-label automatically --%>
<.table rows={@data} is_responsive>
<:col :let={row} label="Column Name">{row.value}</:col>
</.table>
<%!-- Combine with table variants --%>
<.table rows={@data} is_responsive is_striped />
<.table rows={@data} is_responsive is_hover />
<%!-- Actions column with button groups --%>
<:action :let={row}>
<.button_group>
<.button size="xs">View</.button>
<.button size="xs">Edit</.button>
</.button_group>
</:action>