List View

Table-like file and folder rows with composable item slots.

Overview

Files.List lays out consumer-owned Files.Item children in the same compact row treatment as the previous Files surface. Cubitt owns the row visuals, selection interaction, focus treatment, upload/error display, and file/folder icon rendering. Consumers own row metadata, filtering, sorting, folder navigation, upload state, and actions.

Usage

import {
  Files,
  type FilesItem,
} from "@tilt-legal/cubitt-components/files";

function FileList({
  items,
  selectedIds,
  setSelectedIds,
}: {
  items: FilesItem[];
  selectedIds: string[];
  setSelectedIds: (ids: string[]) => void;
}) {
  return (
    <Files
      selectedIds={selectedIds}
      onSelectedIdsChange={setSelectedIds}
      selectionMode="multiple"
    >
      <Files.List>
        {items.map((item) => (
          <Files.Item
            item={item}
            key={item.id}
            onOpen={(openedItem) => {
              if (openedItem.kind === "folder") {
                navigateToFolder(openedItem.id);
              }
            }}
          />
        ))}
      </Files.List>
    </Files>
  );
}

List Item

Files.Item renders one file or folder row inside Files.List. Its data state controls only file lifecycle display:

StateDescription
defaultNormal folder, thumbnail, virtual file, or MIME icon display.
loadingSkeleton placeholder row for an item whose data is not ready yet.
uploadingCircular progress treatment. Use progress for the value.
errorFailed upload treatment.

Selection, active highlight, inline rename, drag, drop-target, disabled, hover, and focus are interaction states owned by Files and item props, not FilesItem.state values.

Custom Rows

Files.Item renders sensible default row cells. Consumers can provide children when they need app-specific columns while still reusing the same item slots. Use the header prop to replace or remove the default list header when your custom rows have a different column shape.

<Files.List header={<MyListHeader />}>
  <Files.Item item={item}>
    <div className="flex justify-center">
      <Files.ItemIcon />
    </div>
    <div className="flex min-w-0 items-center gap-1.5 py-2 ps-1 pe-3">
      <Files.ItemName />
      <Files.ItemBadge />
    </div>
    <span>{item.kind === "folder" ? "Folder" : item.mediaType}</span>
    <span>{item.sizeLabel}</span>
    <span>{item.source?.owner}</span>
    <Files.ItemProgress />
  </Files.Item>
</Files.List>

Props

Files.List

PropTypeDefaultDescription
childrenReactNode-Files.Item rows or compatible custom row children.
headerReactNodedefault headerPass null to remove the header or a node to provide a custom header.
classNamestring-Extends the list root.

Also accepts standard div props. Files.List has no items prop.

Files.Item

PropTypeDefaultDescription
itemFilesItem<TSource>-File or folder display data.
onOpen(item, event) => void-Called on double click, or Enter when inline rename is unavailable.
disabledbooleanfalseDisables the item in addition to root and item data disabled state.
childrenReactNode-Optional custom row content built from item slots.
classNamestring-Extends the item root.

Selection is controlled by the root Files props: selectedIds, onSelectedIdsChange, selectionMode, selectionBehavior, and optional canSelect.

On this page