Elements

Table

A set of elements for building structured data tables. Modeled after the shadcn Table component, adapted to the ELEMENTS fluent API using flexbox layout.

The table system consists of 8 elements:

ElementHTML EquivalentExtendsPurpose
Table<table>VerticalGroupTop-level wrapper
TableCaption<caption>BaseElementCaption text
TableHeader<thead>VerticalGroupHeader section
TableBody<tbody>VerticalGroupBody section
TableFooter<tfoot>VerticalGroupFooter section
TableRow<tr>HorizontalGroupRow
TableHead<th>GroupHeader cell
TableCell<td>GroupBody cell

Constructor

new Table(
    new TableCaption("A list of your recent invoices."),
    new TableHeader(
        new TableRow(
            new TableHead("Invoice"),
            new TableHead("Status"),
            new TableHead("Method"),
            new TableHead("Amount")
        )
    ),
    new TableBody(
        new TableRow(
            new TableCell("INV001"),
            new TableCell("Paid"),
            new TableCell("Credit Card"),
            new TableCell("$250.00")
        ),
        new TableRow(
            new TableCell("INV002"),
            new TableCell("Pending"),
            new TableCell("PayPal"),
            new TableCell("$150.00")
        )
    ),
    new TableFooter(
        new TableRow(
            new TableCell("Total"),
            new TableCell(""),
            new TableCell(""),
            new TableCell("$2,500.00")
        )
    )
);

Examples

Column Widths

Cells default to flexGrow = 1 (equal widths). Use Flex() to control per-column widths:

new TableHeader(
    new TableRow(
        new TableHead("Name").Flex(2),       // 2x wide
        new TableHead("Status").Flex(1),     // 1x wide
        new TableHead("Amount").Flex(1)      // 1x wide
    )
),
new TableBody(
    new TableRow(
        new TableCell("John Doe").Flex(2),   // Match header Flex values
        new TableCell("Active").Flex(1),
        new TableCell("$100.00").Flex(1)
    )
)

Data-Driven Rows

Use BindChildren on TableBody to render rows from reactive data:

var Invoices = new ReactiveProperty<Invoice[]>(Array.Empty<Invoice>());

new Table(
    new TableHeader(
        new TableRow(
            new TableHead("Invoice"),
            new TableHead("Amount")
        )
    ),
    new TableBody()
        .BindChildren(
            Invoices,
            inv => new TableRow(
                new TableCell(inv.Id),
                new TableCell(inv.Amount.ToString("C"))
            )
        )
);

Text and Observable Constructors

TableHead, TableCell, and TableCaption accept strings or observables:

var Total = new ReactiveProperty<string>("$0.00");

// String shorthand (wraps in Label internally)
new TableCell("Hello")

// Observable binding
new TableCell(Total)

// Arbitrary children
new TableCell(
    new HorizontalGroup(
        new Image("icons/check"),
        new Label("Paid")
    ).ClassName("gap-1")
)

Custom Styling

new Table(
    new TableHeader(
        new TableRow(
            new TableHead("Name"),
            new TableHead("Role")
        )
    ),
    new TableBody(
        new TableRow(
            new TableCell("Alice"),
            new TableCell("Admin")
        ).ClassName("highlighted")
    )
).ClassName("my-custom-table")

Table

Top-level wrapper. Extends VerticalGroup.

CSS class: table

new Table(children...);

TableCaption

Caption text displayed within the table. Extends BaseElement.

CSS class: table-caption

new TableCaption("Caption text");
new TableCaption();
new TableCaption(observable);
PropTypeDefault
Text?
(string) => TableCaption
-
GetText?
() => string
-
BindText?
(Observable<string>) => TableCaption
-

TableHeader

Header section container. Extends VerticalGroup.

CSS class: table-header

new TableHeader(new TableRow(...));

TableBody

Body section container. Extends VerticalGroup.

CSS class: table-body

new TableBody(row1, row2, row3);
new TableBody().BindChildren(data, item => new TableRow(...));

TableFooter

Footer section container. Extends VerticalGroup.

CSS class: table-footer

new TableFooter(new TableRow(...));

TableRow

Row container with horizontal layout. Extends HorizontalGroup.

CSS class: table-row

new TableRow(cell1, cell2, cell3);

TableHead

Header cell. Extends Group. Sets flexGrow = 1 by default.

CSS class: table-head

new TableHead("Column Name");           // String (wraps in Label)
new TableHead(observable);              // Observable (wraps in Label)
new TableHead(new Label("Custom"));     // Arbitrary children

TableCell

Body cell. Extends Group. Sets flexGrow = 1 by default.

CSS class: table-cell

new TableCell("Value");                 // String (wraps in Label)
new TableCell(observable);              // Observable (wraps in Label)
new TableCell(new Label("Custom"));     // Arbitrary children

Default Styles

The table is borderless by default with minimal styling:

  • No outer border or background — clean, open layout
  • Bold muted header text with a bottom border separator
  • Bottom border between body rows (removed on last row)
  • Footer with top border and bold text
  • Caption centered with muted color