Tables
Data tables with slot-based and collection-based modes, plus striping, hover effects, custom cell rendering, sortable headers, row highlighting, and configurable border radius.
Basic Table (Slot Mode)
Manually define header and rows using slots for full control over table structure.
| Name | Role | |
|---|---|---|
| John Doe | john@example.com | Admin |
| Jane Smith | jane@example.com | Editor |
| Bob Wilson | bob@example.com | Viewer |
<%= bui_table(variant: :primary) do |t| %>
<% t.with_header do |h| %>
<% h.with_cell(label: "Name") %>
<% h.with_cell(label: "Email") %>
<% h.with_cell(label: "Role") %>
<% end %>
<% t.with_row do |r| %>
<% r.with_cell { "John Doe" } %>
<% r.with_cell { "john@example.com" } %>
<% r.with_cell { "Admin" } %>
<% end %>
<% end %>
Striped & Hoverable
Alternating row backgrounds and hover effects for better readability.
| Name | Role | Status | |
|---|---|---|---|
| Alice Johnson | alice@example.com | Admin | Active |
| Bob Wilson | bob@example.com | Editor | Active |
| Carol Davis | carol@example.com | Viewer | Inactive |
| David Brown | david@example.com | Editor | Active |
| Eve Martinez | eve@example.com | Admin | Active |
<%= bui_table(variant: :primary, striped: true, hoverable: true) do |t| %>
<% t.with_header do |h| %>
<% h.with_cell(label: "Name") %>
<% h.with_cell(label: "Email") %>
<% end %>
<% t.with_row do |r| %>
<% r.with_cell { "Alice Johnson" } %>
<% r.with_cell { "alice@example.com" } %>
<% end %>
<% end %>
Table Styles
Default and bordered styles. Bordered adds a colored ring around the table.
Default Style
| Name | Role |
|---|---|
| Alice Johnson | Admin |
| Bob Wilson | Editor |
Bordered Style
| Name | Role |
|---|---|
| Alice Johnson | Admin |
| Bob Wilson | Editor |
<%# Default style %>
<%= bui_table(variant: :primary, style: :default) do |t| %>
<%# ... %>
<% end %>
<%# Bordered style %>
<%= bui_table(variant: :primary, style: :bordered) do |t| %>
<%# ... %>
<% end %>
Table Sizes
Tables come in sm, md, and lg sizes controlling padding and text size.
Size: sm
| Name | Role | |
|---|---|---|
| Alice Johnson | alice@example.com | Admin |
| Bob Wilson | bob@example.com | Editor |
Size: md
| Name | Role | |
|---|---|---|
| Alice Johnson | alice@example.com | Admin |
| Bob Wilson | bob@example.com | Editor |
Size: lg
| Name | Role | |
|---|---|---|
| Alice Johnson | alice@example.com | Admin |
| Bob Wilson | bob@example.com | Editor |
<%= bui_table(variant: :primary, size: :sm) do |t| %>
<%# ... %>
<% end %>
<%= bui_table(variant: :primary, size: :lg) do |t| %>
<%# ... %>
<% end %>
Table Variants
Tables support all semantic color variants. Shown here with primary, accent, and success.
Primary Variant
| Name | Status | |
|---|---|---|
| Alice Johnson | alice@example.com | Active |
| Bob Wilson | bob@example.com | Active |
| Carol Davis | carol@example.com | Inactive |
Accent Variant
| Name | Status | |
|---|---|---|
| Alice Johnson | alice@example.com | Active |
| Bob Wilson | bob@example.com | Active |
| Carol Davis | carol@example.com | Inactive |
Success Variant
| Name | Status | |
|---|---|---|
| Alice Johnson | alice@example.com | Active |
| Bob Wilson | bob@example.com | Active |
| Carol Davis | carol@example.com | Inactive |
<%= bui_table(variant: :primary, striped: true, hoverable: true) do |t| %>
<%# ... %>
<% end %>
<%= bui_table(variant: :accent, striped: true, hoverable: true) do |t| %>
<%# ... %>
<% end %>
<%= bui_table(variant: :success, striped: true, hoverable: true) do |t| %>
<%# ... %>
<% end %>
Collection Mode
Pass a collection of data and define columns for automatic table rendering.
| Name | Role | Status | |
|---|---|---|---|
| Alice Johnson | alice@example.com | Admin | Active |
| Bob Wilson | bob@example.com | Editor | Active |
| Carol Davis | carol@example.com | Viewer | Inactive |
| David Brown | david@example.com | Editor | Active |
| Eve Martinez | eve@example.com | Admin | Active |
<% users = [
{ name: "Alice Johnson", email: "alice@example.com", role: "Admin", status: "Active" },
{ name: "Bob Wilson", email: "bob@example.com", role: "Editor", status: "Active" },
] %>
<%= bui_table(collection: users, variant: :primary, striped: true, hoverable: true) do |t| %>
<% t.with_column(key: :name, label: "Name") %>
<% t.with_column(key: :email, label: "Email") %>
<% t.with_column(key: :role, label: "Role") %>
<% t.with_column(key: :status, label: "Status") %>
<% end %>
Custom Cell Content
Use a block with column definitions to render custom content like badges and buttons in cells.
| Name | Role | Status | Actions | |
|---|---|---|---|---|
| Alice Johnson | alice@example.com | Admin | Active | |
| Bob Wilson | bob@example.com | Editor | Active | |
| Carol Davis | carol@example.com | Viewer | Inactive | |
| David Brown | david@example.com | Editor | Active | |
| Eve Martinez | eve@example.com | Admin | Active |
<%= bui_table(collection: users, variant: :primary, striped: true, hoverable: true) do |t| %>
<% t.with_column(key: :name, label: "Name") %>
<% t.with_column(key: :email, label: "Email") %>
<% t.with_column(key: :role, label: "Role") { |user|
bui_badge(variant: :info, style: :soft) { user[:role] }
} %>
<% t.with_column(key: :status, label: "Status") { |user|
variant = user[:status] == "Active" ? :success : :danger
bui_badge(variant: variant) { user[:status] }
} %>
<% t.with_column(label: "Actions", align: :right) { |user|
bui_button(variant: :primary, size: :xs, style: :outline) { "Edit" }
} %>
<% end %>
Border Radius
Control table corner rounding with the rounded parameter (none, sm, md, lg, xl, full).
Rounded: none
| Name | Role | |
|---|---|---|
| Alice Johnson | alice@example.com | Admin |
| Bob Wilson | bob@example.com | Editor |
Rounded: sm
| Name | Role | |
|---|---|---|
| Alice Johnson | alice@example.com | Admin |
| Bob Wilson | bob@example.com | Editor |
Rounded: md
| Name | Role | |
|---|---|---|
| Alice Johnson | alice@example.com | Admin |
| Bob Wilson | bob@example.com | Editor |
Rounded: lg
| Name | Role | |
|---|---|---|
| Alice Johnson | alice@example.com | Admin |
| Bob Wilson | bob@example.com | Editor |
Rounded: xl
| Name | Role | |
|---|---|---|
| Alice Johnson | alice@example.com | Admin |
| Bob Wilson | bob@example.com | Editor |
<%= bui_table(variant: :primary, rounded: :none) do |t| %>
<%# ... (sharp corners) %>
<% end %>
<%= bui_table(variant: :primary, rounded: :lg) do |t| %>
<%# ... (large rounded corners) %>
<% end %>
<%= bui_table(variant: :primary, rounded: :xl) do |t| %>
<%# ... (extra large rounded corners) %>
<% end %>
Row Highlighting
Highlight specific rows with a variant-colored background. Slot mode uses highlighted: true on individual rows; collection mode uses a row_highlighted proc.
Slot Mode (highlighted: true on specific rows)
| Order # | Customer | Status | Total |
|---|---|---|---|
| ORD-001 | Alice Johnson | Shipped | $299.00 |
| ORD-002 | Bob Smith | Pending Review | $149.50 |
| ORD-003 | Charlie Brown | Delivered | $75.25 |
| ORD-004 | Diana Prince | Pending Review | $512.00 |
Collection Mode (row_highlighted proc)
| Order # | Customer | Status | Total |
|---|---|---|---|
| ORD-001 | Alice Johnson | Shipped | $299.00 |
| ORD-002 | Bob Smith | Pending | $149.50 |
| ORD-003 | Charlie Brown | Delivered | $75.25 |
| ORD-004 | Diana Prince | Pending | $512.00 |
<%# Slot mode: highlight individual rows %>
<%= bui_table(variant: :primary) do |t| %>
<% t.with_row(highlighted: true) do |r| %>
<% r.with_cell { "Highlighted row" } %>
<% end %>
<% end %>
<%# Collection mode: highlight rows with a proc %>
<%= bui_table(
collection: orders,
variant: :warning,
row_highlighted: ->(item) { item[:status] == "Pending" }
) do |t| %>
<% t.with_column(key: :status, label: "Status") %>
<% end %>
Sortable Headers
Header cells can display sort indicators (↑ ascending, ↓ descending, ↕ unsorted). Works in both slot and collection mode.
Slot Mode
| Name ↑ | Email ↕ | Role | Joined ↓ |
|---|---|---|---|
| Alice Johnson | alice@example.com | Admin | 2024-01-15 |
| Bob Smith | bob@example.com | Editor | 2024-02-20 |
| Charlie Brown | charlie@example.com | Viewer | 2024-03-10 |
Collection Mode
| Name ↑ | Email ↕ | Role | Joined ↓ |
|---|---|---|---|
| Alice Johnson | alice@example.com | Admin | 2024-01-15 |
| Bob Smith | bob@example.com | Editor | 2024-02-20 |
| Charlie Brown | charlie@example.com | Viewer | 2024-03-10 |
<%# Slot mode: sortable headers %>
<%= bui_table(variant: :primary) do |t| %>
<% t.with_header do |h| %>
<% h.with_cell(label: "Name", sortable: true, sorted: true, sort_direction: :asc) %>
<% h.with_cell(label: "Email", sortable: true) %>
<% h.with_cell(label: "Role") %>
<% end %>
<% end %>
<%# Collection mode: sortable columns %>
<%= bui_table(collection: users, variant: :info) do |t| %>
<% t.with_column(key: :name, label: "Name", sortable: true, sorted: true, sort_direction: :asc) %>
<% t.with_column(key: :email, label: "Email", sortable: true) %>
<% t.with_column(key: :role, label: "Role") %>
<% end %>
Inside Cards
Embed tables inside CardComponent using body_padding: false and container_classes to remove double card styling.
Bordered Card
Team Members
5 total| Name | Role | Status | |
|---|---|---|---|
| Alice Johnson | alice@example.com | Admin | Active |
| Bob Wilson | bob@example.com | Editor | Active |
| Carol Davis | carol@example.com | Viewer | Inactive |
Collection Mode in Soft Card
| Product | SKU | Price | Stock |
|---|---|---|---|
| Widget A | WA-001 | $29.99 | 142 |
| Widget B | WB-002 | $49.99 | 38 |
| Gadget C | GC-003 | $99.99 | 7 |
<%# Key: use body_padding: false on card, and remove table card styling %>
<%= bui_card(style: :bordered, variant: :primary, body_padding: false) do |card| %>
<% card.with_header { "Team Members" } %>
<% card.with_body do %>
<%= bui_table(
variant: :primary,
container_classes: "shadow-none ring-0 rounded-none"
) do |t| %>
<%# ... table content ... %>
<% end %>
<% end %>
<% card.with_footer { "Footer content" } %>
<% end %>