# List Item

## Usage

List item with label, description, start/end content slots, and interactive patterns.

```ts
import { ListItem } from '@astryx-vue/core/List'
```

One row of a [List](/en/components/list), rendered as an `<li>`. The row draws itself from `label` and `description`, and takes a leading and a trailing slot around them. It stays a plain row until you give it something to do: an `@click` turns the row into a button, `href` turns it into a link, and `interactiveRef` points at a control inside the row that already carries the action.

`ListItem` is the list-shaped entry point to the general row primitive, [Item](/en/components/item). Use `Item` when the row does not live in a list.

## Examples

Common configurations, variations, and states.

### Basic

Basic list items with labels and descriptions. Use this structure for settings, navigation summaries, and other simple collections.

```vue
<script setup lang="ts">
import { List, ListItem } from '@astryx-vue/core/List'
</script>

<template>
  <List header="Account settings" has-dividers>
    <ListItem label="Profile" description="Name, avatar, and bio" />
    <ListItem label="Notifications" description="Email and push alerts" />
    <ListItem label="Security" description="Password and two-factor auth" />
  </List>
</template>
```

### Media

List items with leading avatars and icons. Use startContent for compact visual identifiers that help users scan the collection.

```vue
<script setup lang="ts">
import { Avatar } from '@astryx-vue/core/Avatar'
import { Badge } from '@astryx-vue/core/Badge'
import { Icon } from '@astryx-vue/core/Icon'
import { List, ListItem } from '@astryx-vue/core/List'

function onSelect(): void {}
</script>

<template>
  <List header="Team" has-dividers>
    <ListItem label="Ada Lovelace" description="Design systems engineer" @click="onSelect">
      <template #startContent>
        <Avatar name="Ada Lovelace" size="sm" />
      </template>
      <template #endContent>
        <Badge label="Owner" variant="purple" />
      </template>
    </ListItem>
    <ListItem label="Grace Hopper" description="Platform infrastructure" @click="onSelect">
      <template #startContent>
        <Avatar name="Grace Hopper" size="sm" />
      </template>
      <template #endContent>
        <Badge label="On call" variant="blue" />
      </template>
    </ListItem>
    <ListItem label="Invite teammate" description="Send an invitation to collaborate" @click="onSelect">
      <template #startContent>
        <Icon icon="info" size="sm" color="secondary" />
      </template>
    </ListItem>
  </List>
</template>
```

### Metadata

List items with end-aligned metadata. Use endContent for badges, counts, timestamps, and compact status details.

```vue
<script setup lang="ts">
import { Badge } from '@astryx-vue/core/Badge'
import { Icon } from '@astryx-vue/core/Icon'
import { List, ListItem } from '@astryx-vue/core/List'
import { Text } from '@astryx-vue/core/Text'

function onSelect(): void {}
</script>

<template>
  <List header="Inbox" density="compact" has-dividers>
    <ListItem label="Launch checklist" description="3 tasks still need an owner" is-selected @click="onSelect">
      <template #startContent>
        <Icon icon="check" size="sm" color="success" />
      </template>
      <template #endContent>
        <Badge label="3" variant="blue" />
      </template>
    </ListItem>
    <ListItem label="Security review" description="Waiting on approval" @click="onSelect">
      <template #startContent>
        <Icon icon="warning" size="sm" color="warning" />
      </template>
      <template #endContent>
        <Text color="secondary">
          Yesterday
        </Text>
      </template>
    </ListItem>
    <ListItem label="Old incident report" description="Archived and read-only" is-disabled>
      <template #startContent>
        <Icon icon="copy" size="sm" color="secondary" />
      </template>
      <template #endContent>
        <Text color="secondary">
          Apr 12
        </Text>
      </template>
    </ListItem>
  </List>
</template>
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string \| number` | — | Primary text of the row. A string or a number truncates to one line; use the `label` slot for rich content. |
| `description` | `string \| number` | — | Secondary text below the label, also truncated to one line. Use the `description` slot for several lines or rich content. |
| `density` | `ItemDensity` (`'compact' \| 'balanced' \| 'spacious'`) | inherited from the list | Overrides the density of the surrounding `List`. Outside a list the default is `'balanced'`. |
| `onClick` | `(event: MouseEvent) => void` | — | Click handler. It renders a button that fills the row's content area and turns on the hover and pressed states. Write `@click` in a template. |
| `interactiveRef` | `MaybeRefOrGetter` | — | A ref to a control inside the row that already carries its keyboard access and action, such as a checkbox in `startContent`. The row becomes an enlarged click target that forwards surface clicks to that control and renders no button of its own, so it adds no second tab stop. Mutually exclusive with `onClick` and `href`, which are ignored while it is set. |
| `href` | `string` | — | Link URL. A link element is rendered inside the row. |
| `target` | `'_blank' \| '_self'` | — | Where the link opens, only used with `href`. `_blank` adds `noopener` and `noreferrer` automatically. |
| `rel` | `string` | — | Link relationship tokens, merged with the ones added automatically. |
| `isDisabled` | `boolean` | `false` | Disabled state. The row becomes inert, its content dims, and `aria-disabled="true"` is written. |
| `isSelected` | `boolean` | `false` | Selected state. Written as `aria-selected="true"` when the row's role permits it, and as `aria-current="true"` otherwise. An `aria-current` you pass yourself wins. |
| `swipeActions` | `ItemSwipeActions` | — | Verbs a sideways touch drag uncovers, per side, each `{ label, icon?, onActivate, isDisabled?, variant?, hasRemoval? }`. A mouse never starts the drag. Give every verb a second home inside the row, or it is unreachable by keyboard and by mouse. |
| `swipeBehavior` | `'reveal' \| 'commit'` | `'reveal'` | `reveal` rests the row open and fires the outermost verb on a long drag; `commit` slides the row out and fires on release, with nothing left open. |

## Slots

- `startContent`: content before the label area, such as an icon or an avatar.
- `label`: rich content replacing the `label` prop.
- `description`: rich content replacing the `description` prop.
- `endContent`: content after the label area, such as a badge, a count, or a timestamp.

## Exposed

`element` (the root element), `focus()`, and `blur()`. Focusing lands on the control inside the row that can actually take focus.
