# List View **Category**: react **URL**: https://ui.darkcode.dev/en/docs/react/components/list-view **Source**: https://raw.githubusercontent.com/DarkCode-Developers/darkcode-ui/refs/heads/main/apps/docs/content/docs/en/react/components/(collections)/list-view.mdx > A single-column interactive list with keyboard navigation, selection, and accessible item actions — built on React Aria's GridList. *** ## Import ```tsx import { ListView } from '@darkcode-ui/react'; ``` ## Usage The `ListView` component displays a list of interactive items with built-in keyboard navigation, typeahead search, and selection. Pass your data to the `items` prop and render each row with a function child. ```tsx "use client"; import {Button, ListView} from "@darkcode-ui/react"; import {Icon} from "@iconify/react"; const files = [ {icon: "gravity-ui:file-text", id: "1", name: "Project Proposal.pdf", size: "2.4 MB"}, {icon: "gravity-ui:picture", id: "2", name: "Design Mockups.fig", size: "8.1 MB"}, {icon: "gravity-ui:file", id: "3", name: "Q4 Financial Report.xlsx", size: "1.2 MB"}, {icon: "gravity-ui:picture", id: "4", name: "Team Photo.png", size: "5.7 MB"}, {icon: "gravity-ui:file-text", id: "5", name: "Meeting Notes.docx", size: "342 KB"}, ]; export function Default() { return ( {(file) => (
{file.name} {file.size}
)}
); } ``` ## Anatomy Import the ListView component and access all parts using dot notation. Each `Item` holds an `ItemContent` (icon/avatar + text) and an optional trailing `ItemAction`. Selection checkboxes are rendered automatically when selection is enabled. ```tsx import { ListView, Button } from '@darkcode-ui/react'; {(file) => (
{file.name} {file.size}
)}
``` ## Selection Modes ListView supports three selection modes: `none` (read-only), `single` (radio-style), and `multiple` (checkboxes). Selection checkboxes are rendered automatically when selection is enabled. ```tsx "use client"; import {ListView} from "@darkcode-ui/react"; import {Icon} from "@iconify/react"; const files = [ {icon: "gravity-ui:file-text", id: "1", name: "Project Proposal.pdf", size: "2.4 MB"}, {icon: "gravity-ui:picture", id: "2", name: "Design Mockups.fig", size: "8.1 MB"}, {icon: "gravity-ui:file", id: "3", name: "Q4 Financial Report.xlsx", size: "1.2 MB"}, {icon: "gravity-ui:picture", id: "4", name: "Team Photo.png", size: "5.7 MB"}, ]; function FileList({selectionMode}: {selectionMode: "none" | "single" | "multiple"}) { return ( {(file) => (
{file.name} {file.size}
)}
); } export function SelectionModes() { return (

None

Single

Multiple

); } ``` ## Variants Use the `variant` prop to switch between the two visual styles. - **Primary** (default) — gray background wrapper with surface-tinted rows forming a card shape. - **Secondary** — no wrapper; transparent rows separated by hairline borders with accent selection. ```tsx "use client"; import {ListView} from "@darkcode-ui/react"; import {Icon} from "@iconify/react"; const files = [ {icon: "gravity-ui:file-text", id: "1", name: "Project Proposal.pdf", size: "2.4 MB"}, {icon: "gravity-ui:picture", id: "2", name: "Design Mockups.fig", size: "8.1 MB"}, {icon: "gravity-ui:file", id: "3", name: "Q4 Financial Report.xlsx", size: "1.2 MB"}, ]; function FileList({variant}: {variant: "primary" | "secondary"}) { return ( {(file) => (
{file.name} {file.size}
)}
); } export function Variants() { return (

Primary

Secondary

); } ``` ## Secondary The secondary variant drops the card wrapper for a flatter, divided list — ideal inside panels that already provide their own surface. ```tsx "use client"; import {Button, ListView} from "@darkcode-ui/react"; import {Icon} from "@iconify/react"; const people = [ {avatar: "gravity-ui:person", id: "1", name: "Olivia Martin", role: "Product Designer"}, {avatar: "gravity-ui:person", id: "2", name: "Liam Johnson", role: "Frontend Engineer"}, {avatar: "gravity-ui:person", id: "3", name: "Emma Williams", role: "Engineering Manager"}, {avatar: "gravity-ui:person", id: "4", name: "Noah Brown", role: "Data Scientist"}, ]; export function Secondary() { return ( {(person) => (
{person.name} {person.role}
)}
); } ``` ## Disabled Items Use the `disabledKeys` prop to disable specific items. Disabled items cannot be selected, focused, or interacted with. ```tsx "use client"; import {ListView} from "@darkcode-ui/react"; import {Icon} from "@iconify/react"; const files = [ {icon: "gravity-ui:file-text", id: "1", name: "Project Proposal.pdf", size: "2.4 MB"}, {icon: "gravity-ui:picture", id: "2", name: "Design Mockups.fig", size: "8.1 MB"}, {icon: "gravity-ui:file", id: "3", name: "Q4 Financial Report.xlsx", size: "1.2 MB"}, {icon: "gravity-ui:picture", id: "4", name: "Team Photo.png", size: "5.7 MB"}, {icon: "gravity-ui:file-text", id: "5", name: "Meeting Notes.docx", size: "342 KB"}, ]; export function DisabledItems() { return ( {(file) => (
{file.name} {file.size}
)}
); } ``` ## With Action Bar Combine with [ActionBar](/react/components/action-bar) for bulk selection workflows. The ActionBar appears when items are selected and provides contextual actions. ```tsx "use client"; import type {Selection} from "@darkcode-ui/react"; import {ActionBar, Button, ListView} from "@darkcode-ui/react"; import {Icon} from "@iconify/react"; import {useState} from "react"; const files = [ {icon: "gravity-ui:file-text", id: "1", name: "Project Proposal.pdf", size: "2.4 MB"}, {icon: "gravity-ui:picture", id: "2", name: "Design Mockups.fig", size: "8.1 MB"}, {icon: "gravity-ui:file", id: "3", name: "Q4 Financial Report.xlsx", size: "1.2 MB"}, {icon: "gravity-ui:picture", id: "4", name: "Team Photo.png", size: "5.7 MB"}, {icon: "gravity-ui:file-text", id: "5", name: "Meeting Notes.docx", size: "342 KB"}, ]; export function WithActions() { const [selected, setSelected] = useState(new Set()); const count = selected === "all" ? files.length : selected.size; return ( <> {(file) => (
{file.name} {file.size}
)}
0}> setSelected(new Set())} /> ); } ``` ## Virtualization For very large datasets, pass `virtualized` (and optionally `rowHeight`) to render only the visible rows. Give the list a fixed height so it can scroll. ```tsx {(file) => {/* ... */}} ``` ## CSS Classes ### Base Classes - `.list-view` — Root container. Sets `min-height: 0`, full width, and `outline: none`. - `.list-view--primary` — Gray background wrapper with padding and large border-radius. Rows tint with the surface color. - `.list-view--secondary` — No background or padding. Rows are transparent with bottom borders. ### Element Classes - `.list-view__item` — Individual row. Flex layout with gap, padding, and interactive states. - `.list-view__item-content` — Main content area (icon + text). Flex with `min-width: 0` for truncation. - `.list-view__title` — Primary text. Truncated, `text-sm font-medium`. - `.list-view__description` — Secondary text. Truncated, `text-xs text-muted`. - `.list-view__item-action` — Trailing action slot. Auto-margin to the end. - `.list-view__selection-cell` — Checkbox area. Fixed width, flex-shrink: 0. - `.list-view__selection-control` — The selection checkbox (circular in single-selection mode). - `.list-view__empty-state` — Centered empty-state container. ### Interactive States - **Hover**: `bg-surface/40` (primary) or `bg-default/50` (secondary). - **Selected**: `bg-surface/70` (primary) or `bg-accent-soft` (secondary). - **Focus visible**: Inset focus ring via `box-shadow: inset 0 0 0 2px var(--focus)`. - **Disabled**: `status-disabled` utility. - **Dragging**: `opacity: 0.5`. ## API Reference ### ListView The root list component. Accepts a generic type parameter `T` for the item data shape. Extends RAC `GridListProps`. | Prop | Type | Default | Description | |------|------|---------|-------------| | `aria-label` | `string` | — | Accessible label for the list. Required. | | `variant` | `'primary' \| 'secondary'` | `'primary'` | Visual variant. | | `selectionMode` | `'none' \| 'single' \| 'multiple'` | `'none'` | Item selection mode. | | `selectedKeys` | `Selection` | — | Controlled selected item keys. | | `defaultSelectedKeys` | `Selection` | — | Default selected keys (uncontrolled). | | `onSelectionChange` | `(keys: Selection) => void` | — | Callback when selection changes. | | `selectionBehavior` | `'toggle' \| 'replace'` | `'toggle'` | Selection interaction model. | | `items` | `Iterable` | — | Item objects for dynamic collections. | | `disabledKeys` | `Iterable` | — | Keys of items that should be disabled. | | `onAction` | `(key: Key) => void` | — | Callback when a user performs an action on an item. | | `renderEmptyState` | `() => ReactNode` | — | Render function for the empty state. | | `virtualized` | `boolean` | `false` | Enable row virtualization for large datasets. | | `rowHeight` | `number` | `56` | Estimated row height in pixels for virtualization. | | `className` | `string` | — | Additional CSS classes. | | `children` | `ReactNode \| ((item: T) => ReactNode)` | — | Static items or render function for dynamic collections. | ### ListView.Item Individual list item. Extends RAC `GridListItemProps`. | Prop | Type | Default | Description | |------|------|---------|-------------| | `id` | `Key` | — | Unique item identifier. | | `textValue` | `string` | — | String representation for typeahead and accessibility. | | `isDisabled` | `boolean` | — | Whether the item is disabled. | | `href` | `string` | — | URL to navigate to when the item is actioned. | | `children` | `ReactNode` | — | Item content — typically `ItemContent` and optionally `ItemAction`. | | `className` | `string` | — | Additional CSS classes. | ### ListView.ItemContent Main content container for the item (icon/avatar + text). ### ListView.Title Primary text element inside an item. ### ListView.Description Secondary/muted text element inside an item. ### ListView.ItemAction Trailing action slot inside an item. ## Related Components - **Listbox**: Scrollable list of selectable items - **Table**: Structured data display in rows and columns - **Checkbox**: Binary choice input control ## Accessibility ListView is built on the React Aria `GridList` primitive and provides: - Full keyboard navigation (Arrow keys, Home, End, Page Up/Down, type-ahead) - Single and multiple selection with `Space`/`Enter` and modifier keys - Roving tabindex and proper `row` / `gridcell` roles - Disabled item handling that skips focus and interaction For more information, see the [React Aria GridList documentation](https://react-spectrum.adobe.com/react-aria/GridList.html).