UmbHost.Tables
17.3.0
Prefix Reserved
See the version list below for details.
dotnet add package UmbHost.Tables --version 17.3.0
NuGet\Install-Package UmbHost.Tables -Version 17.3.0
<PackageReference Include="UmbHost.Tables" Version="17.3.0" />
<PackageVersion Include="UmbHost.Tables" Version="17.3.0" />
<PackageReference Include="UmbHost.Tables" />
paket add UmbHost.Tables --version 17.3.0
#r "nuget: UmbHost.Tables, 17.3.0"
#:package UmbHost.Tables@17.3.0
#addin nuget:?package=UmbHost.Tables&version=17.3.0
#tool nuget:?package=UmbHost.Tables&version=17.3.0
UmbHost.Tables
A table property editor for Umbraco 17 and 18 that allows content editors to create and manage tabular data with support for header rows, header columns, and inline editing.
Version compatibility
The package major tracks the Umbraco major, so pick the line that matches your site:
| Umbraco | UmbHost.Tables | Branch |
|---|---|---|
| 18.x | 18.x | main |
| 17.x | 17.x | v17/main |
This branch is the 17.x maintenance line.
Features
- Inline cell editing with contenteditable
- Header row and header column toggles
- Add and remove rows and columns
- Right-click context menu for quick operations
- Strongly-typed C# models with PropertyValueConverter
- Configurable min/max rows and columns
- Read-only mode support
- Built with Lit/Vite/TypeScript following Umbraco 17 patterns
Installation
Install the NuGet package:
dotnet add package UmbHost.Tables
Or via the Package Manager Console:
Install-Package UmbHost.Tables
Usage
Creating a Data Type
- In the Umbraco backoffice, go to Settings → Data Types
- Click Create Data Type
- Select Table as the property editor
- Configure your options (header toggles, row/column limits, etc.)
- Save the Data Type
Adding to a Document Type
- Edit your Document Type
- Add a new property
- Select your Table Data Type
- Save the Document Type
Rendering in Razor Views
@using UmbHost.Tables.Models
@{
var table = Model.Value<TableModel>("tableProperty");
}
@if (table != null && table.Rows.Any())
{
<table class="table">
@if (table.UseFirstRowAsHeader && table.Rows.Any())
{
<thead>
<tr>
@foreach (var cell in table.Rows.First().Cells)
{
<th>@Html.Raw(cell.Value)</th>
}
</tr>
</thead>
}
<tbody>
@foreach (var row in table.UseFirstRowAsHeader ? table.Rows.Skip(1) : table.Rows)
{
<tr>
@for (var i = 0; i < row.Cells.Count; i++)
{
var cell = row.Cells[i];
if (table.UseFirstColumnAsHeader && i == 0)
{
<th>@Html.Raw(cell.Value)</th>
}
else
{
<td>@Html.Raw(cell.Value)</td>
}
}
</tr>
}
</tbody>
</table>
}
Setup
Add these to Views/_ViewImports.cshtml once:
@using UmbHost.Tables.Models
@using UmbHost.Tables.Extensions
@using UmbHost.Tables.Rendering
@addTagHelper *, UmbHost.Tables
ToHtmlTable needs the first two usings, TableHtmlOptions needs the third, and the tag helper needs the addTagHelper line.
Using the Tag Helper
@{
var table = Model.Value<TableModel>("tableProperty");
}
<umbhost-table table="@table" class="table table-striped" />
class, id, data-* and any other attribute you write are passed straight through to the rendered <table>. Inner elements have their own class hooks:
<umbhost-table table="@table"
class="table table-striped"
id="prices"
data-sortable="true"
head-class="thead-dark"
body-class="table-group-divider"
row-class="align-middle"
header-cell-class="fw-bold"
cell-class="px-4 py-2" />
Nothing is rendered when the table is null or empty, so no @if guard is needed.
Using the Extension Method
@{
var table = Model.Value<TableModel>("tableProperty");
}
@table.ToHtmlTable("table table-striped")
For full control, pass TableHtmlOptions instead of a class string:
@table.ToHtmlTable(new TableHtmlOptions
{
Class = "table table-striped",
Id = "prices",
CellClass = "px-4 py-2",
Attributes = new Dictionary<string, string?> { ["data-sortable"] = "true" },
})
ToHtmlTable returns IHtmlContent, so @Html.Raw(table.ToHtmlTable("table")) also works.
Generated Markup
Both helpers produce the same markup. Header cells are determined by cell.Type or the UseFirstRowAsHeader / UseFirstColumnAsHeader flags, and carry scope for screen readers:
<table class="table table-striped">
<thead>
<tr>
<th scope="col">Plan</th>
<th scope="col">Price</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Starter</th>
<td><a href="/pricing/">£10</a></td>
</tr>
</tbody>
</table>
Models
TableModel
The main model representing the table:
| Property | Type | Description |
|---|---|---|
Rows |
IReadOnlyList<TableRow> |
Collection of table rows |
UseFirstRowAsHeader |
bool |
Whether the first row should render as <th> elements |
UseFirstColumnAsHeader |
bool |
Whether the first column should render as <th> elements |
RowCount |
int |
Number of rows |
ColumnCount |
int |
Number of columns (from first row) |
HasContent |
bool |
Whether the table has at least one row containing a non-empty cell |
IsEmpty |
bool |
Inverse of HasContent |
Cells |
IReadOnlyList<IReadOnlyList<TableCell>> |
The rows projected to a two-dimensional list of cells |
HeaderRow |
TableRow? |
The first row when UseFirstRowAsHeader is true, otherwise null |
BodyRows |
IReadOnlyList<TableRow> |
The rows excluding the header row when UseFirstRowAsHeader is true, otherwise every row |
HeaderColumn |
IReadOnlyList<TableCell> |
The first cell of every row when UseFirstColumnAsHeader is true, otherwise empty |
Methods:
| Method | Returns | Description |
|---|---|---|
GetCell(int rowIndex, int columnIndex) |
TableCell? |
The cell at the given position, or null if either index is out of bounds |
GetRow(int index) |
TableRow? |
The row at the given index, or null if out of bounds |
GetColumn(int columnIndex) |
IReadOnlyList<TableCell> |
Every cell in the column, skipping rows that have too few cells |
TableRow
Represents a single row:
| Property | Type | Description |
|---|---|---|
Cells |
IReadOnlyList<TableCell> |
Collection of cells in the row |
IsHeaderRow |
bool |
Whether every cell in the row is a header |
IsEmpty |
bool |
Whether all cells are empty |
CellCount |
int |
Number of cells |
TableCell
Represents a single cell:
| Property | Type | Description |
|---|---|---|
Value |
string |
HTML/text content |
Type |
TableCellType |
Td or Th |
ColSpan |
int |
Column span. Reserved; cell spanning is not implemented, so this is always 1 |
RowSpan |
int |
Row span. Reserved; cell spanning is not implemented, so this is always 1 |
IsEmpty |
bool |
Whether cell is empty |
IsHeader |
bool |
Whether cell is a header |
IsSpanned |
bool |
Whether the cell spans multiple rows or columns. Always false while spanning is unimplemented |
Configuration Options
When creating a Data Type, the following options are available:
| Option | Default | Description |
|---|---|---|
showUseFirstRowAsHeader |
true |
Show the "use first row as header" toggle |
showUseFirstColumnAsHeader |
true |
Show the "use first column as header" toggle |
defaultRows |
3 |
Initial number of rows for new tables |
defaultColumns |
3 |
Initial number of columns for new tables |
minRows |
1 |
Minimum allowed rows |
maxRows |
0 |
Maximum allowed rows (0 = unlimited) |
minColumns |
1 |
Minimum allowed columns |
maxColumns |
0 |
Maximum allowed columns (0 = unlimited) |
Requirements
- Umbraco 17.0.0 or later
- .NET 10.0 or later
Development
Prerequisites
- .NET 10 SDK
- Node.js 18+
Building from Source
Clone the repository and build the client assets:
cd UmbHost.Tables.Client/
npm install
npm run build
Build the .NET project:
dotnet build
Watching for Changes
During development, you can watch for client-side changes:
cd UmbHost.Tables.Client/
npm run watch
Creating a NuGet Package
dotnet pack UmbHost.Tables/UmbHost.Tables.csproj -c Release
Migrating from Limbo.Umbraco.Tables
If you're migrating from Limbo.Umbraco.Tables:
- The data structure is compatible, so existing content should work without migration
- Update your using statements from
Limbo.Umbraco.Tables.ModelstoUmbHost.Tables.Models - The
TableModelproperties are largely the same - Update your Data Types to use the new "Table" property editor
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Credits
Inspired by Limbo.Umbraco.Tables by Limbo.
Built for Umbraco 17+ by UmbHost.
Support
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Umbraco.Cms.Core (>= 17.5.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.