# List

**`sonic-list`** renders one row per entry of its `props` array, either set directly or loaded with `fetch`. In TypeScript, prefer the `.items` row renderer (with `.separator` · `.noItems` · `.skeleton`); `<template>` children are for plain HTML hosts without Lit. Each row gets its own data provider at `<dataProvider>/list-item/<index>`.

## Basic example

Add `fetch` to load `props` from `serviceURL` + `endPoint` (or `dataProvider` when `endPoint` is empty). `key` picks the array inside the response. Without `fetch`, the list only renders the `props` it receives.

<sonic-code>
  <template>
    <sonic-list fetch serviceURL="/docs-mock-api" dataProvider="flights?direction=arrivals" key="flights" class="grid gap-1">
      <template>
        <div class="text-sm" data-bind ::inner-html="<b>$time</b> $code from $city ($airport)"></div>
      </template>
    </sonic-list>
  </template>
</sonic-code>

This example uses HTML templates; from Lit, use the [row renderer](#row-renderer) instead. Fetch attributes (`lazyload` · `refetchEveryMs` · headers · authentication) are shared with [Fetch](/core/components/functional/fetch).

## Row renderer

From a Lit component, set `.items` to a function `(item, metadata) => TemplateResult`. Functions only pass as properties, so always use the `.` binding: the same applies to `.separator` · `.noItems` · `.skeleton`. `metadata` holds `key` · `even` · `odd` · `firstChild` · `lastChild` · `onlyChild`.

<docs-lit-demo for="docs-list-alternate-demo"></docs-lit-demo>

## Row variants

In HTML, `templateKey` (default `template`) names the row field that selects a `<template data-value="…">`. Rows without a match cycle through the `<template>` children that have no `data-value`. From Lit, branch inside the `items` callback instead.

<sonic-code>
  <template>
    <sonic-list fetch serviceURL="/docs-mock-api" dataProvider="flights?direction=departures" key="flights" templateKey="status" class="grid gap-1">
      <template>
        <div class="text-sm" data-bind ::inner-html="$code to $city"></div>
      </template>
      <template data-value="delayed">
        <div class="text-sm text-warning" data-bind ::inner-html="$code to $city: delayed"></div>
      </template>
      <template data-value="cancelled">
        <div class="text-sm text-danger line-through" data-bind ::inner-html="$code to $city"></div>
      </template>
    </sonic-list>
  </template>
</sonic-code>

## Separator and empty list

`.separator` renders between rows (not after the last one). `.noItems` renders when the array is empty. In HTML, use `<template data-value="separator">` and `<template data-value="no-item">`.

<docs-lit-demo for="docs-list-separator-demo"></docs-lit-demo>

## Limit and offset

`limit` caps the number of rendered rows and `offset` skips the first ones, without changing the data. With no `limit`, every row is rendered.

<sonic-code>
  <template>
    <sonic-list fetch serviceURL="/docs-mock-api" dataProvider="flights?direction=departures" key="flights" limit="3" class="grid gap-1">
      <template>
        <div class="text-sm" data-bind ::inner-html="<b>$time</b> $code to $city"></div>
      </template>
    </sonic-list>
  </template>
</sonic-code>

## Objects and `extractValues`

When the data is an object, the list wraps it in a one-row array. Add `extractValues` to render one row per property instead, as `{ key, value }`.

<docs-lit-demo for="docs-list-extract-values-demo"></docs-lit-demo>

## Loading state

With no `loader`, nothing is shown while fetching. Set `loader` (`fixed`) or `loader="inline"` to show a [Loader](/core/components/ui/loader), or provide `.skeleton` / `<template skeleton>` to render placeholder rows; a skeleton replaces the loader. Call `invalidate()` on the list publisher to fetch again.

<sonic-code>
  <template>
    <sonic-list fetch loader="inline" serviceURL="/docs-mock-api" dataProvider="flights?direction=arrivals&status=landed" key="flights" class="grid gap-1">
      <template>
        <div class="text-sm" data-bind ::inner-html="$code from $city: landed"></div>
      </template>
    </sonic-list>
  </template>
</sonic-code>

## API reference

| Attribute | Values | Description |
|-----------|--------|-------------|
| `dataProvider` | string | Publisher of the list. Also the endpoint when `endPoint` is empty. Inherited from ancestors |
| `fetch` | boolean | Loads `props` from the API. Without it, the list never fetches |
| `serviceURL` · `endPoint` · `key` | string | Request configuration, see [Fetch](/core/components/functional/fetch) |
| `templateKey` | string (default `template`) | Row field that selects a `<template data-value>` |
| `extractValues` | boolean | Renders an object as one `{ key, value }` row per property |
| `limit` | number (default unlimited) | Maximum number of rendered rows |
| `offset` | number (default `0`) | Index of the first rendered row |
| `loader` | `fixed` (when empty) · `inline` | Loader shown while fetching. None by default |
| `debug` | boolean | Shows each row's data on hover |

Properties (TypeScript / Lit, preferred):

| Property | Type | Description |
|----------|------|-------------|
| `props` | array · object | Rows to render |
| `items` | `(item, metadata) => TemplateResult` | Row renderer |
| `separator` | `() => TemplateResult` | Rendered between rows |
| `noItems` | `() => TemplateResult` | Rendered when there are no rows |
| `skeleton` | `() => TemplateResult` | Rendered while fetching |
| `itemPropertyMap` | object | `propertyMap` passed to each row subscriber |

Templates (plain HTML hosts):

| Template | Description |
|----------|-------------|
| `<template>` | Row markup; several are used in turn |
| `<template data-value="…">` | Row variant selected by `templateKey` |
| `<template data-value="separator">` | Between rows |
| `<template data-value="no-item">` | Empty list |
| `<template skeleton>` | While fetching |

| Event | Description |
|-------|-------------|
| `loading` | A fetch starts |
| `load` | Data is loaded and assigned to `props` |
