# xpl-list-item

Single row for [`xpl-list`](../xpl-list/readme.md). **Slot-based** rows expose `role="listitem"` on the inner row surface (`.xpl-list-item__wrapper` or `.xpl-list-item__listitem-shell` when `href` is set); **legacy** `item` rows use `role="listitem"` on the host. Hand-written integration notes for slots, attributes, and events live in the [list readme](../xpl-list/readme.md); the section below is Stencil-generated API for this component.

**Reorder handle (slot mode):** When `reorderable` is enabled and the row uses **slot-based** content, the handle is an **`xpl-button`** wrapping a native **`<button>`**. Reorder logic is wired on the **`xpl-button` host** (`mousedown` / `keydown`); those events originate on the inner `<button>` and **bubble** to the host, which is how the list item receives them today. If `xpl-button` ever stopped bubbling for those events, reorder handlers would need to attach directly to the inner button (similar to `componentDidRender` syncing `aria-*` on that element).

**Legacy `item` prop:** Prop-driven rows **do not** render the reorder handle, radios, or keyboard reorder affordances. Parent `xpl-list` **does not** set `selectable`, `radio-name`, or `reorderable` on those rows (those attributes are removed so they are not mistaken for supported behavior). Use slots if you need selection, drag, or keyboard reorder.

### Accessibility

- **`role="listitem"`** is on the inner row surface (`.xpl-list-item__wrapper` for non-link rows, `.xpl-list-item__listitem-shell` for link rows), not on the `<xpl-list-item>` host. This avoids older browser issues with `display: contents` and ARIA.
- **Hidden rows** render an empty host with the native `hidden` attribute only — no `role="listitem"` — so hidden rows are removed from the accessibility tree entirely.
- **Selectable rows** render `xpl-radio` with an accessible label derived from the **title** slot text, falling back to `Select <item-id>`, then `Select list item`.
- **Reorder handle** (`xpl-button`) syncs `aria-label` and `aria-pressed` on the inner native `<button>` via `componentDidRender`. Labels change between drag and keyboard modes.
- **Focus indicators** use `:focus-visible` with `outline-color: var(--xpl-border-focus)` and `outline-2 outline-offset-2`.
- **Disabled rows** use `--xpl-background-action-disabled` and `--xpl-text-disabled`; link anchors get `pointer-events: none`.
- **Keyboard reorder**: Enter/Space activates mode, ArrowUp/ArrowDown moves the row, Escape exits.

### Design tokens

| Role | Token |
|------|-------|
| Row background | `--xpl-background-surface-default` |
| Row border | `--xpl-border-default` (default), `--xpl-border-hover` (hover), `--xpl-border-negative` (error), `--xpl-border-focus` (focus/drag-over) |
| Row border-radius | `--xpl-border-radius-default` |
| Text | `--xpl-text-default` (primary), `--xpl-text-subdued` (metadata/details), `--xpl-text-negative` (error), `--xpl-text-disabled` |
| Icon | `--xpl-icon-subtle` (chevron) |
| Spacing | `--xpl-space-4` through `--xpl-space-40` (padding, gap, margins) |
| Sizing | `--xpl-size-050` (dot badge), `--xpl-size-350` (min-height) |
| Typography | `--xpl-font-size-body`, `--xpl-font-size-title-5`, `--xpl-font-size-callout`, `--xpl-font-size-caption` |
| Disabled background | `--xpl-background-action-disabled` |
| Selected background | `--xpl-background-surface-subtle` |
| Drag opacity | `--xpl-opacity-75` (custom token in `:root`) |

<!-- Auto Generated Below -->


## Properties

| Property            | Attribute             | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                             | Type                                                                                                                          | Default     |
| ------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------- |
| `disabled`          | `disabled`            | Whether the item is disabled.                                                                                                                                                                                                                                                                                                                                                                                                                                           | `boolean`                                                                                                                     | `false`     |
| `error`             | `error`               | Whether to show the item in an error state.                                                                                                                                                                                                                                                                                                                                                                                                                             | `boolean`                                                                                                                     | `false`     |
| `hidden`            | `hidden`              | When true, the row is not shown and does not participate in visible-only list behavior (e.g. `orderChange` / `orderedItemIds`, reorder targets). Use for filtering, conditional display, or keeping stable `item-id` while the row is off-screen. See `xpl-list` readme “Hidden rows”.  **Accessibility:** Renders an empty host with the native `hidden` attribute only (no `role="listitem"`), consistent with the row not participating as a list item while hidden. | `boolean`                                                                                                                     | `false`     |
| `href`              | `href`                | URL for link behavior. When provided, the entire row becomes clickable. Clicks on `actions` or `avatar` slots are prevented from triggering navigation.                                                                                                                                                                                                                                                                                                                 | `string`                                                                                                                      | `undefined` |
| `item`              | --                    | Optional item data for prop-based rendering. When provided, this takes precedence over slotted content and renders using the legacy ListItem interface. **Deprecated.** Prefer slot-based composition (named slots on `xpl-list-item`).                                                                                                                                                                                                                                 | `ListItem`                                                                                                                    | `undefined` |
| `itemId`            | `item-id`             | Unique identifier for this item. Used for selection and drag/drop. Mutable so the host can sync from `item-id` / `id` in `componentWillLoad` without breaking one-way data flow.                                                                                                                                                                                                                                                                                        | `string`                                                                                                                      | `undefined` |
| `keyboardActive`    | `keyboard-active`     | When set by the parent, indicates this item is the active keyboard reorder item.                                                                                                                                                                                                                                                                                                                                                                                        | `boolean`                                                                                                                     | `false`     |
| `radioName`         | `radio-name`          | Name attribute for radio inputs (shared across selectable items in a list).                                                                                                                                                                                                                                                                                                                                                                                             | `string`                                                                                                                      | `undefined` |
| `reorderable`       | `reorderable`         | Whether this item is reorderable (shows a drag handle in **slot-based** layout). When the deprecated `item` prop is used, legacy markup has **no** reorder handle even if this is true.                                                                                                                                                                                                                                                                                 | `boolean`                                                                                                                     | `false`     |
| `selectable`        | `selectable`          | Whether this item is selectable (shows `xpl-radio` in a shared group).                                                                                                                                                                                                                                                                                                                                                                                                  | `boolean`                                                                                                                     | `false`     |
| `selected`          | `selected`            | Whether this item is selected (radio checked state).                                                                                                                                                                                                                                                                                                                                                                                                                    | `boolean`                                                                                                                     | `false`     |
| `showDivider`       | `show-divider`        | Whether to show a divider below the item.                                                                                                                                                                                                                                                                                                                                                                                                                               | `boolean`                                                                                                                     | `false`     |
| `titleBadgeVariant` | `title-badge-variant` | Optional badge to display next to the title (dot badge). Only used when `item` prop is not provided (slot mode). Matches `xpl-badge` variant values (e.g. purple, green, red).                                                                                                                                                                                                                                                                                          | `"blue" \| "error" \| "gray" \| "green" \| "inactive" \| "orange" \| "purple" \| "red" \| "success" \| "warning" \| "yellow"` | `undefined` |


## Events

| Event           | Description                                                             | Type                                                   |
| --------------- | ----------------------------------------------------------------------- | ------------------------------------------------------ |
| `itemDragEnd`   | Emitted when a drag operation ends on this item (after drop or cancel). | `CustomEvent<{ itemId?: string; item: HTMLElement; }>` |
| `itemDragStart` | Emitted when drag starts on this item.                                  | `CustomEvent<{ itemId?: string; item: HTMLElement; }>` |
| `itemDrop`      | Emitted when an item is dropped on this item.                           | `CustomEvent<{ itemId?: string; item: HTMLElement; }>` |
| `itemSelect`    | Emitted when the item is selected (radio change).                       | `CustomEvent<{ itemId?: string; }>`                    |


## Dependencies

### Used by

 - [xpl-list](..)

### Depends on

- [xpl-avatar](../../xpl-avatar)
- [xpl-icon](../../xpl-icon)
- [xpl-badge](../../xpl-badge)
- [xpl-button](../../xpl-button)
- [xpl-radio](../../xpl-radio)
- [xpl-divider](../../xpl-divider)

### Graph
```mermaid
graph TD;
  xpl-list-item --> xpl-avatar
  xpl-list-item --> xpl-icon
  xpl-list-item --> xpl-badge
  xpl-list-item --> xpl-button
  xpl-list-item --> xpl-radio
  xpl-list-item --> xpl-divider
  xpl-avatar --> xpl-badge
  xpl-button --> xpl-icon
  xpl-list --> xpl-list-item
  style xpl-list-item fill:#f9f,stroke:#333,stroke-width:4px
```

----------------------------------------------

*Built with [StencilJS](https://stenciljs.com/)*
