The empty ledger body a data table shows when a query returns no rows.
<app-table-empty-state title="No results" text="Try a different filter." />
When a data table has loaded but its query returned no rows, the body shouldn't be a blank gap under the headers. <app-table-empty-state> fills that space with a centred icon, a title, and a line of guidance — the table's own version of an empty state, styled to sit cleanly inside the ledger.
Its look comes entirely from the shared @webority/theme, so the Razor <app-table-empty-state> and the React <AppTableEmptyState> render identically — the same empty ledger on every Webority surface.
Playground
Every attribute, live. Each change re-renders the real tag helper on the server, so the markup underneath is the exact call that produced the empty row above it.
Anatomy
An icon, a title, and optional guidance text — shown in place of table rows when there are none.
An empty ledger
It explains what would appear here once there's data, so an empty table never reads as broken. It sits below the header, inside the same wrap.
Reference
Project
Status
Updated
No assessments yet
Risk assessments saved against this project appear here.
It sits below the header, pinned inside the scrollerKeep the table headers in place and show the empty state below them, as a sibling of the table inside .table-wrap, wrapped in .tbl-empty-block — never in a <td colSpan>. The theme pins that block with position: sticky, so a wide column set scrolls the header alone while the centred message stays put and the scrollbar sits at the bottom of the wrap.
With an action
When there's a natural first step — invite a teammate, add a record — hand the empty state an action so the user can act without leaving the table.
An action inside the empty body
Child markup on the tag becomes the action slot (.tbl-empty-action), matching React's action prop.
Name
Email
Role
No team members
Invite colleagues to collaborate on assessments.
Show code
<div class="table-wrap">
<table class="table table-ledger"><thead>…</thead></table>
<div class="tbl-empty-block">
<app-table-empty-state icon="users"
title="No team members"
text="Invite colleagues to collaborate on assessments.">
<app-button size="sm" left-icon="plus">Invite member</app-button>
</app-table-empty-state>
</div>
</div>
When to use
Use it when
A data table finished loading and returned zero rows.
A filtered or searched table has no matches and you want to say so in place.
The table has a natural first action (add / invite) worth surfacing when it's empty.
Reach for something else when
The empty area is a card or section, not a table body. → AppEmptyState
The table is still loading its first page. → AppSkeletonRows
The rows failed to load because of an error. → AppAlert
Best practices
Do
Reference
Date
Status
No matches
No assessments match these filters. Try widening the date range.
A filter-empty names the reason and suggests the fix — the user knows what to change.
Don't
Reference
Date
Status
No data
A bare "No data" leaves the user unsure whether the table is empty, broken, or mis-filtered.
Do
Name
Email
Role
No team members
Invite colleagues to collaborate.
When the table has an obvious next step, the empty state offers it right there.
Don't
Name
Email
Role
No team members
There are no team members. There are no team members to show in this list right now.
Padding the text instead of offering the invite action wastes the moment.
Every option
The whole surface of the component, one cell per value — including the glyph-name-only limit Razor's icon attribute has (React additionally accepts a custom node).
icon — the glyph set
icon="inbox"
No results
icon="file-text"
No results
icon="search"
No results
icon="users"
No results
icon="cloud-slash"
No results
content
title only
No results
title + text
No results
Try adjusting your filters.
title + text + action
No team members
Invite colleagues to collaborate.
text — long copy wraps inside the ledger
No assessments yet
Risk assessments saved against this project appear here, along with any drafts your team started but hasn't submitted.
icon slot — string vs custom node
icon="stars"
Glyph name
custom node — React only; Razor's icon is always a Bootstrap Icons name
Glyph name only
icon is glyph-name-only in RazorReact's icon prop also accepts a custom React node (a product's own icon set); the Razor icon attribute always resolves through IconMarkup.Render against a Bootstrap Icons name — there's no equivalent escape hatch server-side.
in context
below a 4-column header
Reference
Project
Status
Updated
No results
below a narrow 2-column header
Name
Role
No members
Attributes
Attribute
Type
Default
Description
title
string
—
The heading — what would appear here.
icon
string
—
Bootstrap Icons glyph for the bubble (React icon). Glyph-name-only in Razor — React additionally accepts a custom node.
text
string
—
Supporting line of guidance below the title (body copy).
(content)
markup
—
Child markup rendered as the action slot (.tbl-empty-action) — matches React's action prop.