---
title: List
description: A grouped list with rows, routing and custom templates.
---
import Source from './_generated/list.mdx';

A grouped list of rows with leading/trailing content, subtitles, chevrons, and an optional link mode.

<DemoFrame component="list" />

## Installation

```bash
npx touchcn add list
```

## Usage

<CodeGroup>

```html Angular
<tcn-list>
  <tcn-list-item chevron>
    <svg item-leading><!-- … --></svg>
    Wi-Fi
    <span item-subtitle>Connected</span>
  </tcn-list-item>
  <tcn-list-item [link]="['/about']" chevron>About</tcn-list-item>
</tcn-list>
```

```tsx React
import { TcnList, TcnListItem } from '@/components/ui/list';

<TcnList>
  <TcnListItem leading={<WifiIcon />} subtitle="Connected" chevron>
    Wi-Fi
  </TcnListItem>
  <TcnListItem chevron>
    <Link to="/about">About</Link>
  </TcnListItem>
</TcnList>
```

```vue Vue
<script setup lang="ts">
import { TcnList, TcnListItem } from '@/components/ui/list';
</script>

<template>
  <TcnList>
    <TcnListItem subtitle="Connected" chevron>
      <template #leading><WifiIcon /></template>
      Wi-Fi
    </TcnListItem>
    <TcnListItem chevron>
      <RouterLink to="/about">About</RouterLink>
    </TcnListItem>
  </TcnList>
</template>
```

</CodeGroup>

## Section header & footer

`TcnListHeader` and `TcnListFooter` are flat siblings of `tcn-list` — a header labels the
group above it (uppercase caption on iOS, sentence-case subheader on Material), a footer adds
a caption below it. The header takes an optional trailing slot for an action.

<CodeGroup>

```html Angular
<tcn-list-header>
  Notifications
  <button header-trailing tcnButton variant="ghost" size="sm">See all</button>
</tcn-list-header>
<tcn-list>
  <tcn-list-item>Push</tcn-list-item>
</tcn-list>
<tcn-list-footer>Choose how you want to be notified.</tcn-list-footer>
```

```tsx React
import { TcnList, TcnListItem, TcnListHeader, TcnListFooter } from '@/components/ui/list';

<TcnListHeader trailing={<TcnButton variant="ghost" size="sm">See all</TcnButton>}>
  Notifications
</TcnListHeader>
<TcnList>
  <TcnListItem>Push</TcnListItem>
</TcnList>
<TcnListFooter>Choose how you want to be notified.</TcnListFooter>
```

```vue Vue
<script setup lang="ts">
import { TcnList, TcnListItem, TcnListHeader, TcnListFooter } from '@/components/ui/list';
</script>

<template>
  <TcnListHeader>
    Notifications
    <template #trailing>
      <TcnButton variant="ghost" size="sm">See all</TcnButton>
    </template>
  </TcnListHeader>
  <TcnList>
    <TcnListItem>Push</TcnListItem>
  </TcnList>
  <TcnListFooter>Choose how you want to be notified.</TcnListFooter>
</template>
```

</CodeGroup>

## Props

**`TcnListItem`**

| Prop       | Type        | Default | Description                                       |
| ---------- | ----------- | ------- | ------------------------------------------------- |
| `leading`  | slot / `ReactNode` | — | Leading content (Angular: `[item-leading]`).      |
| `subtitle` | slot / `ReactNode` | — | Secondary line (Angular: `[item-subtitle]`).      |
| `trailing` | slot / `ReactNode` | — | Trailing content (Angular: `[item-trailing]`).    |
| `chevron`  | `boolean`   | `false` | Show a disclosure chevron.                        |
| `link`     | `string \| unknown[]` | — | Render the whole row as a single link.       |

:::warning
A linked row renders as one `<a>`. Don't nest interactive controls (button, switch, input) inside it —
use a plain (non-link) item for rows with trailing controls.
:::

**`TcnListHeader`**

| Prop       | Type               | Default | Description                                          |
| ---------- | ------------------ | ------- | ---------------------------------------------------- |
| `trailing` | slot / `ReactNode` | —       | Trailing action, end-aligned (Angular: `[header-trailing]`). |

<Source />
