Table
Table Component
Section titled “Table Component”The Table component provides a composable API for creating accessible,
semantic HTML tables with support for expandable rows, nested tables,
and flexible customization.
It is designed for displaying structured data using native HTML table elements while maintaining accessibility, reusable subcomponents, and full control over table interactions.
Features
Section titled “Features”- Composable table API: Build structured tables using
Table.Head,Table.HeaderCell,Table.Row, andTable.Cell. - Semantic HTML markup: Uses native table elements (
table,thead,tr,th, andtd) for improved accessibility and SEO. - Expandable table rows: Reveal additional information dynamically below individual rows.
- Nested tables support: Display related datasets inside expandable sections.
- Flexible styling: Apply custom classes and styles to any table element.
Table Component Usage Example
Section titled “Table Component Usage Example”| Transaction | Invoices | |
|---|---|---|
| 291246 | 1 | |
| 291072 | 2 |
<script lang="ts"> import { Button, Table } from "@fefade-ui/svelte" import { Constants } from "@fefade-ui/core" import { SvelteSet } from "svelte/reactivity"
let invoicesData = $state([ { id: 107268, customerId: 9, transactionId: 291246, amount: "20.5", status: "Pending", installment: "1/1", installmentNumber: "1", createdAt: "2024-10-16T00:00:00-03:00", expiresAt: "2024-11-15T00:00:00-03:00" }, { id: 107179, customerId: 9, transactionId: 291072, amount: "35.38", status: "Pending", installment: "1/2", installmentNumber: "1", createdAt: "2024-10-14T00:00:00-03:00", expiresAt: "2024-11-13T00:00:00-03:00" }, { id: 107180, customerId: 9, transactionId: 291072, amount: "11.38", status: "Pending", installment: "2/2", installmentNumber: "1", createdAt: "2024-10-15T00:00:00-03:00", expiresAt: "2024-11-14T00:00:00-03:00" } ])
const groupedInvoices = $derived( Map.groupBy(invoicesData, (invoice) => invoice.transactionId) )
const expandedRows = new SvelteSet<number>()
function toggleRow(index: number) { if (expandedRows.has(index)) { expandedRows.delete(index) } else { expandedRows.add(index) } }</script>
<Table> <Table.Head> <Table.Row> <Table.HeaderCell>Transaction</Table.HeaderCell> <Table.HeaderCell>Invoices</Table.HeaderCell> <Table.HeaderCell></Table.HeaderCell> </Table.Row> </Table.Head>
<tbody> {#each groupedInvoices as [transactionId, invoices] (transactionId)} <Table.Row onclick={() => toggleRow(transactionId)} style="cursor:pointer; user-select: none;" > <Table.Cell style="display: flex; gap: 1rem; align-items: center; justify-content: center;" > <Table.ExpandButton expanded={expandedRows.has(transactionId)} /> {transactionId} </Table.Cell>
<Table.Cell> {invoices.length} </Table.Cell>
<Table.Cell> <Button disabled>Disabled</Button> </Table.Cell> </Table.Row>
{#if expandedRows.has(transactionId)} {@const borderStyle = `border: 1px solid ${Constants.themeColorVar.border};`} <Table.Row> <Table.Cell colspan={3}> <Table> <Table.Head> <Table.Row> <Table.HeaderCell style={borderStyle}>ID</Table.HeaderCell> <Table.HeaderCell style={borderStyle}> Status </Table.HeaderCell> <Table.HeaderCell style={borderStyle}>Value</Table.HeaderCell> <Table.HeaderCell style={borderStyle}> Installment </Table.HeaderCell> </Table.Row> </Table.Head>
<tbody> {#each invoices as invoice (invoice.id)} <Table.Row> <Table.Cell style={borderStyle}> {invoice.id} </Table.Cell> <Table.Cell style={borderStyle}> {invoice.status} </Table.Cell> <Table.Cell style={borderStyle}> {invoice.amount} </Table.Cell> <Table.Cell style={borderStyle}> {invoice.installment} </Table.Cell> </Table.Row> {/each} </tbody> </Table> </Table.Cell> </Table.Row> {/if} {/each} </tbody></Table>Table Subcomponents
Section titled “Table Subcomponents”| Component | Description |
|---|---|
Table | Root container for the HTML table. |
Table.Head | Wrapper for the table header (thead). |
Table.HeaderCell | Table header cell component (th). |
Table.Row | Table row component (tr). |
Table.Cell | Table data cell component (td). |
Table.ExpandButton | Expandable row toggle indicator. |
Table Component Props
Section titled “Table Component Props”| Component | Prop | Type | Default | Description |
|---|---|---|---|---|
Table | class | string | "" | Additional CSS classes applied to the table element. |
Table.HeaderCell | colspan | number | 1 | Number of columns the header cell spans. |
Table.HeaderCell | class | string | "" | Additional CSS classes applied to the header cell. |
Table.Row | class | string | "" | Additional CSS classes applied to the table row. |
Table.Row | onclick | function | — | Optional click handler for row interactions. |
Table.Cell | colspan | number | 1 | Number of columns the table cell spans. |
Table.Cell | class | string | "" | Additional CSS classes applied to the table cell. |
Table.ExpandButton | expanded | boolean | false | Controls the expanded state of the toggle indicator. |
Expandable Table Rows
Section titled “Expandable Table Rows”The Table component supports expandable rows by allowing applications to
manage expansion state externally and render additional Table.Row elements
when needed.
The Table.ExpandButton component works as a visual indicator for expandable
content. The expansion behavior and state management remain fully controlled by
your application.
Accessible HTML Tables Best Practices
Section titled “Accessible HTML Tables Best Practices”- Use semantic HTML table elements to improve accessibility and search engine understanding.
- Use
Table.HeaderCellfor column labels instead of regular data cells. - Keep row interactions predictable and provide clear visual feedback.
- Use
Table.ExpandButtonto indicate expandable table content. - Render expanded content inside a dedicated
Table.Rowwith aTable.Cellspanning all columns. - Use nested tables only for related structured data that benefits from hierarchical presentation.