Item
Item is a single data row of a
Dependencies
When to use
Set a stable row identifier from your own data whenever rows can be sorted, filtered, reordered, or paginated, since the fallback used when it's unset stays correct only while row order never changes. A dedicated pinning flag pins an individual row (a totals row, typically) to the bottom of the table's own scroll container, and the consumer marks which row or rows, rather than the table guessing "the last one" from DOM order, which would break the moment rows are re-sorted or a new one is appended.
Clicking a row fires a row-click event, unless the owning table is in selection mode (at least one row already checked), where a click toggles that row's own selection instead. Its selection state and the sticky-column flags are all pushed down by the owning table itself, so never set them directly.
Install & usage
npm install @eunomia/elements
import "@eunomia/elements/table-item.js";
import "@eunomia/elements/table-cell.js";
<eun-table-item row-key="1">
<eun-table-cell>Ada Lovelace</eun-table-cell>
<eun-table-cell>Active</eun-table-cell>
</eun-table-item>
<script type="module">
document
.querySelector("eun-table-item")
.addEventListener("euntablerowclick", (event) => console.log(event.rowKey));
</script>
Everything beyond the checkbox (every eun-table-cell and whatever you
slot into slot="action") is markup you author yourself.
Properties
Item <eun-table-item>
Attributes
| Name | Type | Default | Description |
|---|---|---|---|
| row-key | string | — | This row's stable identity, used for selection tracking. Falls back to a DOM-order-derived key when unset, which is unstable across client-side sort or filter, so set this explicitly for any such table |
| sticky-bottom | boolean | false | Pins this row to the bottom of its scroll container, such as a totals row. The consumer marks which rows, rather than the table inferring the last row from DOM order |
Import the exact TypeScript type behind any property above, see
Slots
| Name | Description |
|---|---|
| (default) | Table cell elements, one per column |
| action | Optional trailing action content, such as a button or a dropdown button, revealed on hover or focus, or always with the owning table's actionAlwaysVisible. Hidden and inert (unfocusable, unclickable) while any row is selected either way |
Events
| Name | Type | Description |
|---|---|---|
| euntablerowclick | TableRowClickEvent | Fired on a row click outside its checkbox or action cell and outside selection mode, whether or not this row or the owning table has any row-end action at all |
Every event above follows the same naming convention, covered in
CSS custom properties
| Name | Description |
|---|---|
| --table-row-background | Sets the background color |
| --table-row-hover-background | Sets the background color on hover |
| --table-row-selected-background | Sets the background color while selected |
| --table-sticky-row-background | Sets the background color of this row while stickyBottom, at rest. Falls back to table-row-background |
| --table-sticky-column-background | Sets the background color of this row's sticky first or last column cell, and its checkbox cell once the owning table is selectable, at rest. Falls back to table-row-background |
| --table-checkbox-background | Sets the background color of this row's own unchecked checkbox, once the owning table is selectable |
| --table-checkbox-hover | Sets the background color of this row's own unchecked checkbox while hovered, once the owning table is selectable |
| --table-sticky-border-color | Sets the border color of this row's own top edge while stickyBottom, falling back to table-border-color, and of the trailing edge of the always-sticky checkbox cell and any sticky first or last column cell, transparent by default |
| --table-action-color | Sets the text and icon color of a row-end action, bridging into a slotted button's or dropdown button's own text color |
| --table-sync-overlay-color | Sets the highlight color of the shimmer sweep shown while the owning table's syncing is set |
| --table-sync-duration | Sets the duration of the syncing shimmer sweep, as a CSS time, defaulting to 1.6 seconds |
Row-end action: dropdown vs. plain button
slot="action" accepts anything: most often a eun-dropdown-button for
several choices, or a single eun-button when there's only ever one thing
to do. Both are ordinary slotted content, so nothing stops one row from
using a dropdown and another a plain button in the very same table (see
each on its own below), and a mix of both together. Hover or focus a row
to reveal its own trailing control.
Several choices: a dropdown button
<!-- A row whose action opens a menu of several choices -->
<eun-table-item row-key="1">
<eun-table-cell>Ada Lovelace</eun-table-cell>
<eun-table-cell><eun-tag severity="success">Active</eun-tag></eun-table-cell>
<eun-dropdown-button
slot="action"
size="xs"
appearance="ghost"
icon="more_vert"
aria-label="Row actions"
.options=${[
{ key: "edit", label: "Edit" },
{ key: "archive", label: "Archive" },
]}
></eun-dropdown-button>
</eun-table-item>
Exactly one thing to do: a plain button
<!-- A row whose action is a single, one-click operation -->
<eun-table-item row-key="2">
<eun-table-cell>Grace Hopper</eun-table-cell>
<eun-table-cell><eun-tag severity="warning">Pending</eun-tag></eun-table-cell>
<eun-button
slot="action"
size="xs"
appearance="ghost"
aria-label="Resend invite"
@click="${()"
=""
>
resendInvite(row)} >
<eun-icon name="mail" size="16"></eun-icon>
</eun-button>
</eun-table-item>
Mixed in the same table
Nothing stops one row from using a dropdown and another a plain button, in the very same table, since each row's own action is entirely independent.
Pinned row
Give the table a bounded height (here 220px, via inline style or
--table-max-height) so there's actually something to scroll: 8 team rows
below don't all fit at once. Scroll the demo and watch the Total row stay
pinned to the bottom the whole way, while every other row scrolls normally
underneath it, exactly the "pin a totals row" case sticky-bottom is
for.
<eun-table style="max-height: 220px;">
<eun-table-header>
<eun-table-column width="1fr">Team</eun-table-column>
<eun-table-column width="120px">Budget</eun-table-column>
</eun-table-header>
<eun-table-item row-key="1">
<eun-table-cell>Engineering</eun-table-cell>
<eun-table-cell>$120k</eun-table-cell>
</eun-table-item>
<!-- ...6 more rows... -->
<eun-table-item row-key="total" sticky-bottom style="font-weight: 600;">
<eun-table-cell>Total</eun-table-cell>
<eun-table-cell>$430k</eun-table-cell>
</eun-table-item>
</eun-table>
role="row", with aria-selected reflecting selected while the owning
table is selectable. It participates in the owning eun-table's
roving-tabindex grid. See
:hover and :focus-within, so a
keyboard user tabbing toward either sees it appear before activating it.