SimpleList

Render a list of records as a vertical, mobile-friendly list — typically used as a child of <List> or <ReferenceManyField>.

Installation

pnpm dlx shadcn@latest add @shadmin/simple-list

Usage

<SimpleList> uses render-prop slots to produce each row. The slots receive the current record and return any React node:

import { List, SimpleList } from "@/components/admin";
 
export const PostList = () => (
  <List>
    <SimpleList
      primaryText={(record) => record.title}
      secondaryText={(record) => `${record.views} views`}
      tertiaryText={(record) =>
        new Date(record.published_at).toLocaleDateString()
      }
    />
  </List>
);

By default each row links to the edit page of the record. Pass linkType="show" to link to the show page instead, or linkType={false} to disable the link entirely.

<SimpleList> reads its data and loading state from the parent <ListContext>, so it must be rendered inside a <List> (or any other component that exposes a list context).

Props

PropRequiredTypeDefaultDescription
primaryTextOptional(record, id) => ReactNode-Main text for the row
secondaryTextOptional(record, id) => ReactNode-Subtext rendered under the primary text
tertiaryTextOptional(record, id) => ReactNode-Short label rendered next to the primary text (typically a date)
leftAvatarOptional(record, id) => ReactNode-Element rendered as an avatar to the left of the text
leftIconOptional(record, id) => ReactNode-Icon rendered to the left of the text
rightIconOptional(record, id) => ReactNode-Icon rendered at the right of the row
linkTypeOptional"edit" | "show" | false"edit"Where to link each row
emptyOptionalReactNode<ListNoResults />Element rendered when the list is empty
loadingOptionalReactNode<SimpleListLoading />Element rendered while the list is loading
classNameOptionalstring-Extra Tailwind classes appended to the root <ul>

primaryText, secondaryText, tertiaryText

Each text slot is a function that receives the record (and its identifier) and returns a React node:

<SimpleList
  primaryText={(record) => record.title}
  secondaryText={(record) => `${record.views} views`}
  tertiaryText={(record) => new Date(record.published_at).toLocaleDateString()}
/>

leftAvatar, leftIcon, rightIcon

Use these slots to add a leading avatar, a leading icon, or a trailing icon:

import { BookOpen, Star } from "lucide-react";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
 
<SimpleList
  leftAvatar={(record) => (
    <Avatar>
      <AvatarFallback>{record.title.charAt(0)}</AvatarFallback>
    </Avatar>
  )}
  leftIcon={() => <BookOpen className="size-5" />}
  rightIcon={(record) => (
    <div className="flex items-center gap-1">
      <Star className="size-4 fill-yellow-400 text-yellow-400" />
      {record.rating}
    </div>
  )}
  primaryText={(record) => record.title}
/>;

linkType

Where to link when the user clicks a row. Defaults to "edit". Pass "show" to link to the show page, or false to disable the link:

<SimpleList primaryText={(record) => record.title} linkType="show" />
 
<SimpleList primaryText={(record) => record.title} linkType={false} />

empty

What to render when the list is empty. Defaults to <ListNoResults>:

<SimpleList
  primaryText={(record) => record.title}
  empty={<div>No posts.</div>}
/>

loading

What to render while the list is loading. Defaults to a <SimpleListLoading> skeleton sized after the configured slots.