# ListCell
A versatile cell component used for displaying content in a list format, supporting various layouts and interactions.
## Import
```tsx
import { ListCell } from '@coinbase/cds-web/cells/ListCell'
```
## Examples
### Overview
A ListCell row is divided into the following 5 columns:
- Media
- Title & description
- Intermediary
- End (detail & subdetail or action)
- Accessory
#### Basic Usage
```tsx live
```
:::tip
Prefer `spacingVariant="condensed"` for the new ListCell design. The `compact` may be removed in a future major release.
:::
#### Spacing Variant
```tsx live
{/* Preferred (new design) */}
}
onClick={console.log}
title="Condensed"
variant="positive"
/>
{/* Deprecated options kept for backward compatibility */}
}
onClick={console.log}
title="Compact (deprecated)"
variant="positive"
/>
}
onClick={console.log}
title="Normal"
variant="positive"
/>
```
### Media
::::note
We have deprecated `CellMedia`; pass media directly as shown below.
::::
#### Leading Icon
```tsx live
}
/>
```
#### Leading Avatar
```tsx live
}
/>
```
### Title & Description
#### Title Line Limits
- In condensed spacing (`spacingVariant="condensed"`), the title shows up to two lines by default, regardless of whether a description is present.
- In normal and compact spacing, the title shows up to two lines when there is no description; if a description is present, the title is limited to one line.
- Use `disableMultilineTitle` to force the title to one line in all cases.
::::warning
The `title` and `description` props are rendered inside a CDS `Text` with default fonts and truncation. To render arbitrary React nodes without being wrapped by a ``, use `titleNode` and `descriptionNode`.
When using the Node props, you are responsible for styling, layout, and truncation behavior.
::::
#### Custom Title/Description via Node Props
```tsx live
}
titleNode={
Verified account
}
descriptionNode={
Composed description with any React nodes
}
/>
```
#### Multiline Description
```tsx live
```
### Intermediary
```tsx live
function Intermediary() {
const dimensions = { width: 62, height: 18 };
const sparklineData = prices
.map((price) => parseFloat(price))
.filter((price, index) => index % 10 === 0);
const referenceY = sparklineData[Math.floor(sparklineData.length / 3)];
const CompactChart = memo(
({ data, color = 'var(--color-fgPositive)', showArea = false, referenceY }) => (
),
);
return (
}
spacingVariant="condensed"
title="Bitcoin"
description="BTC"
intermediary={}
detail="$334,239.03"
subdetail="+4.06%"
priority="start"
variant="positive"
/>
);
}
```
### End
#### Detail and Subdetail
```tsx live
```
::::warning
Like `title` and `description`, `detail` and `subdetail` props are also rendered inside a CDS `Text` with default fonts. To render arbitrary React nodes without being wrapped by a ``, use `detailNode` and `subdetailNode`.
::::
#### Custom Detail/Subdetail via Node Props
```tsx live
}
title="Custom end content"
description="Detail and subdetail rendered with custom nodes"
detailNode={
$12,345.00
}
subdetailNode={
+5.43%
}
/>
```
#### End Action
When you pass the `end` prop, it overrides the `detail`/`subdetail`/`detailNode`/`subdetailNode`.
```tsx live
{
alert('Action clicked');
}}
>
Action
}
/>
```
### Accessory
#### Interactive Cell with Accessory
```tsx live
alert('Cell clicked!')}
/>
```
#### Custom Accessory via Node Prop
```tsx live
}
end={
}
accessoryNode={
}
/>
```
### Accessibility Label
The accessibility props are only applied when the `` has a value for the `onClick` prop. Otherwise, content passed into the `` must use accessibility props and attributes as needed.
```tsx live
}
media={}
onClick={() => window.alert('ListCell clicked!')}
title="BTC"
spacingVariant="condensed"
/>
}
media={}
title="BTC"
spacingVariant="condensed"
/>
```
### Helper text
```tsx live
This is a default helper message.
}
media={}
end={}
/>
This is a warning message.
}
media={}
end={}
/>
This is an error message.
}
media={}
end={}
/>
```
### Loading States
The ListCellFallback component provides loading state representations of ListCell. It uses placeholder rectangles to indicate where content will appear, creating a smooth loading experience. The web version uses percentage-based widths and custom layouts to match the ListCell's four-column structure.
```tsx live
{/* Basic loading state */}
{/* Loading state with media */}
{/* Loading state with details */}
{/* Full loading state with custom widths */}
```
### Priority
The priority prop controls which parts of the cell are protected from shrinking and truncation when horizontal space is limited. It accepts start, middle, and end as a string or an array of strings.
```tsx live
function PriorityContent() {
const dimensions = { width: 62, height: 18 };
const sparklineData = prices
.map((price) => parseFloat(price))
.filter((price, index) => index % 10 === 0);
const referenceY = sparklineData[Math.floor(sparklineData.length / 3)];
const CompactChart = memo(
({ data, color = 'var(--color-fgPositive)', showArea = false, referenceY }) => (
),
);
return (
}
detail="$334,239.03"
subdetail="+4.06%"
priority="start"
variant="positive"
/>
}
detail="$334,239.03"
subdetail="+4.06%"
priority="middle"
variant="positive"
/>
}
detail="$334,239.03"
subdetail="+4.06%"
priority="end"
variant="positive"
/>
}
detail="$334,239.03"
subdetail="+4.06%"
priority={['start', 'middle', 'end']}
variant="warning"
/>
);
}
```
### Anatomy
Without helper text (top-only layout):
```text
┌───────────────────────────────────────────────────────────────────────────┐
│ root (Box) │
│┌─────────────────────────────────────────────────────────────────────────┐│
││ pressable ││
││┌───────────────────────────────────────────────────────────────────────┐││
│││ contentContainer & mainContent (HStack) │││
│││ ┌─────┐ ┌────────────────┐ ┌────────────┐ ┌────────────┐ ┌─────────┐ │││
│││ │media│ │ VStack │ │intermediary│ │ end │ │accessory│ │││
│││ │ │ │ ┌──────────┐ │ │ │ │ (detail │ │ │ │││
│││ │ │ │ │ title │ │ │ │ │ or │ │ │ │││
│││ │ │ │ └──────────┘ │ │ │ │ action) │ │ │ │││
│││ │ │ │ ┌────────────┐ │ │ │ │ │ │ │ │││
│││ │ │ │ │ description│ │ │ │ │ │ │ │ │││
│││ │ │ │ └────────────┘ │ │ │ │ │ │ │ │││
│││ └─────┘ └────────────────┘ └────────────┘ └────────────┘ └─────────┘ │││
││└───────────────────────────────────────────────────────────────────────┘││
│└─────────────────────────────────────────────────────────────────────────┘│
└───────────────────────────────────────────────────────────────────────────┘
```
With helper text (top + bottom layout):
```text
┌─────────────────────────────────────────────────────────────────────────────┐
│ root (Box) │
│┌───────────────────────────────────────────────────────────────────────────┐│
││ pressable ││
││┌─────────────────────────────────────────────────────────────────────────┐││
│││ contentContainer (VStack) │││
│││┌───────────────────────────────────────────────────────────────────────┐│││
││││ mainContent (HStack) ││││
││││ ┌─────┐ ┌────────────────┐ ┌────────────┐ ┌────────────┐ ┌─────────┐ ││││
││││ │media│ │ VStack │ │intermediary│ │ end │ │accessory│ ││││
││││ │ │ │ ┌──────────┐ │ │ │ │ (detail │ │ │ ││││
││││ │ │ │ │ title │ │ │ │ │ or │ │ │ ││││
││││ │ │ │ └──────────┘ │ │ │ │ action) │ │ │ ││││
││││ │ │ │ ┌────────────┐ │ │ │ │ │ │ │ ││││
││││ │ │ │ │ description│ │ │ │ │ │ │ │ ││││
││││ │ │ │ └────────────┘ │ │ │ │ │ │ │ ││││
││││ └─────┘ └────────────────┘ └────────────┘ └────────────┘ └─────────┘ ││││
│││└───────────────────────────────────────────────────────────────────────┘│││
│││┌───────────────────────────────────────────────────────────────────────┐│││
││││ helperText ││││
│││└───────────────────────────────────────────────────────────────────────┘│││
││└─────────────────────────────────────────────────────────────────────────┘││
│└───────────────────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────────────────┘
```
Mapping to `styles` / `classNames` keys:
- root: outer `Box` wrapping the entire cell
- pressable: interactive overlay when `href` / `onClick` keyboard handlers are present
- contentContainer: container around top and optional bottom content
- mainContent: inner horizontal layout that holds the main pieces
- title/description: stacked text column within `topContent`
- media: leading media container
- intermediary: middle container between main and end
- end: container for `detail` / `subdetail` or `end` prop you pass in
- accessory: trailing accessory container
- helperText: container below main content to display helper text
## Props
| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `accessory` | `more \| selected \| arrow` | No | `-` | Accessory to display at the end of the cell. |
| `accessoryNode` | `null \| string \| number \| false \| true \| ReactElement> \| Iterable \| ReactPortal` | No | `-` | Custom accessory node rendered at the end of the cell. Takes precedence over accessory. |
| `action` | `null \| string \| number \| false \| true \| ReactElement> \| Iterable \| ReactPortal` | No | `-` | - |
| `alignContent` | `ResponsiveProp