A stateless table cell Web Component. Works standalone today and coordinates with future x-table-row / x-table components via bubbling events.
<x-table-cell>Cell content</x-table-cell>
<x-table-cell type="header" sortable sort-direction="asc">
Name
</x-table-cell>
| Attribute | Type | Default | Description |
|---|---|---|---|
type | "data" \| "header" | "data" | Cell semantic type. "header" maps to columnheader/rowheader ARIA role; "data" maps to cell. |
scope | "col" \| "row" \| "colgroup" \| "rowgroup" | "col" | Header scope. Determines whether a header is a columnheader or rowheader. Meaningful only when type="header". |
align | "start" \| "center" \| "end" | "start" | Horizontal content alignment. |
valign | "top" \| "middle" \| "bottom" | "middle" | Vertical content alignment. |
col-span | positive integer | 1 | Number of grid columns the cell spans. Sets style.gridColumn="span N" on the host for CSS Grid parents. |
row-span | positive integer | 1 | Number of grid rows the cell spans. Sets style.gridRow="span N" on the host. |
truncate | boolean (presence) | false | Truncates overflowing text with an ellipsis. |
sticky | "none" \| "start" \| "end" | "none" | Sticky column. "start" sticks to the inline-start edge; "end" to the inline-end edge. Requires an opaque --x-table-cell-sticky-bg. |
sortable | boolean (presence) | false | Shows the sort button. Only effective when type="header". |
sort-direction | "none" \| "asc" \| "desc" | "none" | Current sort state. Updates the sort icon and aria-sort. |
disabled | boolean (presence) | false | Disables interactions and applies reduced opacity. |
| Property | Type | Reflects | Default |
|---|---|---|---|
type | string | type attribute | "data" |
scope | string | scope attribute | "col" |
align | string | align attribute | "start" |
valign | string | valign attribute | "middle" |
colSpan | number | col-span attribute | 1 |
rowSpan | number | row-span attribute | 1 |
truncate | boolean | truncate attribute | false |
sticky | string | sticky attribute | "none" |
sortable | boolean | sortable attribute | false |
sortDirection | string | sort-direction attribute | "none" |
disabled | boolean | disabled attribute | false |
x-table-cell-sortFired when the sort button is activated. The component is stateless — the consumer must update the sort-direction attribute to reflect the new state.
| Property | Value |
|---|---|
| Bubbles | true |
| Composed | true |
| Cancelable | true |
Detail:
{
direction: "asc" | "desc" | "none"; // the next direction
previousDirection: "none" | "asc" | "desc";
}
Calling event.preventDefault() cancels the action; the attribute will not be updated externally.
x-table-cell-connectedFired on every connectedCallback. Consumed by future x-table-row to discover and track cells.
| Property | Value |
|---|---|
| Bubbles | true |
| Composed | true |
| Cancelable | false |
Detail: { type, scope, colSpan, rowSpan, align }
x-table-cell-disconnectedFired on every disconnectedCallback.
| Property | Value |
|---|---|
| Bubbles | true |
| Composed | true |
| Cancelable | false |
Detail: {}
| Name | Description |
|---|---|
| (default) | Cell content |
sort-icon | Custom sort icon; replaces the default inline SVG arrows. |
| Part | Element | Description |
|---|---|---|
cell | div | Outer layout wrapper; receives padding, background, border. |
content | span | Content area wrapping the default slot. |
sort-btn | button | Sort interaction button (visible for header+sortable cells only). |
sort-icon-default | span | Default inline SVG sort icon (neutral/ascending/descending). |
| Property | Default | Description |
|---|---|---|
--x-table-cell-padding | 0.5rem 0.75rem | Cell padding. |
--x-table-cell-border-width | 1px | Border width (bottom border). |
--x-table-cell-min-width | 0 | Minimum cell width. |
--x-table-cell-max-width | none | Maximum cell width. |
| Property | Default (light) | Default (dark) | Description |
|---|---|---|---|
--x-table-cell-bg | transparent | transparent | Data cell background. |
--x-table-cell-header-bg | rgba(0,0,0,0.04) | rgba(255,255,255,0.06) | Header cell background. |
--x-table-cell-border-color | rgba(0,0,0,0.1) | rgba(255,255,255,0.1) | Border color. |
--x-table-cell-color | inherit | inherit | Data cell text color. |
--x-table-cell-header-color | inherit | inherit | Header cell text color. |
--x-table-cell-sort-color | rgba(0,0,0,0.4) | rgba(255,255,255,0.4) | Sort icon default color. |
--x-table-cell-sort-hover-color | rgba(0,0,0,0.7) | rgba(255,255,255,0.7) | Sort icon hover color. |
--x-table-cell-sticky-bg | #ffffff | #1f2937 | Sticky cell background (must be opaque). |
--x-table-cell-focus-ring | rgba(59,130,246,0.5) | same | Sort button focus ring. |
| Property | Default | Description |
|---|---|---|
--x-table-cell-font-size | inherit | Cell font size. |
--x-table-cell-header-font-weight | 600 | Header cell font weight. |
| Property | Default | Description |
|---|---|---|
--x-table-cell-transition-duration | 150ms | Sort button color transition duration. |
| Property | Default | Description |
|---|---|---|
--x-table-cell-disabled-opacity | 0.45 | Opacity when disabled. |
type | scope | role on host |
|---|---|---|
"data" | any | "cell" |
"header" | "col" (default) | "columnheader" |
"header" | "colgroup" | "columnheader" |
"header" | "row" | "rowheader" |
"header" | "rowgroup" | "rowheader" |
aria-sortSet on the host element when either sortable is present or sort-direction is not "none":
sort-direction | aria-sort |
|---|---|
"none" | "none" |
"asc" | "ascending" |
"desc" | "descending" |
When neither sortable nor a non-"none" direction is set, aria-sort is removed.
aria-disabledSet to "true" on the host when disabled is present.
The sort button's aria-label describes the action that will occur on activation, not the current state:
Current sort-direction | Button aria-label |
|---|---|
"none" | "Sort ascending" |
"asc" | "Sort descending" |
"desc" | "Remove sort" |
| Key | Target | Action |
|---|---|---|
Enter / Space | Sort button | Activates sort, fires x-table-cell-sort |
The component is stateless — clicking the sort button fires x-table-cell-sort and does nothing else. The consumer must update the sort-direction attribute:
cell.addEventListener('x-table-cell-sort', (e) => {
// e.detail.direction is the next direction
cell.setAttribute('sort-direction', e.detail.direction);
});
Direction cycles: "none" → "asc" → "desc" → "none".
To cancel a sort action (e.g. for async validation):
cell.addEventListener('x-table-cell-sort', (e) => {
e.preventDefault(); // sort-direction is not updated
});
When x-table-cell is placed in a CSS Grid context (as provided by a future x-table-row), setting col-span and row-span drives the cell's grid placement:
col-span="2" → style.gridColumn = "span 2" on the hostrow-span="3" → style.gridRow = "span 3" on the host1 clears the inline style (no span)<!-- Spans 2 columns in an x-table-row grid -->
<x-table-cell col-span="2">Wide cell</x-table-cell>
Sticky cells require an opaque background. The --x-table-cell-sticky-bg custom property controls this:
x-table-cell {
--x-table-cell-sticky-bg: #ffffff; /* or match your row background */
}
<x-table-cell sticky="start">Frozen first column</x-table-cell>
Note: sticky positioning requires a scrollable ancestor container.
When x-table-row and x-table are implemented, they will consume the x-table-cell-connected and x-table-cell-disconnected events to track cells. The cell fires these unconditionally — no configuration needed.
<x-table-cell>Hello world</x-table-cell>
<x-table-cell type="header" sortable sort-direction="none">
Name
</x-table-cell>
<script>
document.querySelector('x-table-cell').addEventListener('x-table-cell-sort', (e) => {
e.target.setAttribute('sort-direction', e.detail.direction);
});
</script>
<x-table-cell truncate style="width: 150px;">
This is a very long text that will be truncated
</x-table-cell>
<div style="display: grid; grid-template-columns: repeat(4, 1fr);">
<x-table-cell col-span="2">Spans two columns</x-table-cell>
<x-table-cell>Col 3</x-table-cell>
<x-table-cell>Col 4</x-table-cell>
</div>
<x-table-cell sticky="start"
style="--x-table-cell-sticky-bg: #fff;">
Row label
</x-table-cell>
<x-table-cell type="header" sortable>
Status
<svg slot="sort-icon" width="16" height="16" viewBox="0 0 16 16">
<path d="M8 4l4 8H4l4-8z" fill="currentColor"/>
</svg>
</x-table-cell>
const cell = document.querySelector('x-table-cell');
// Property access
cell.type = 'header';
cell.sortable = true;
cell.sortDirection = 'asc';
cell.colSpan = 2;
cell.disabled = false;
// Events
cell.addEventListener('x-table-cell-sort', (e) => {
cell.sortDirection = e.detail.direction;
});
[:x-table-cell {:type "header" :sortable "" :sort-direction "none"
:on-x-table-cell-sort #(set! (.-sortDirection (.-target %))
(.-direction (.-detail %)))}
"Column Name"]
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |