ReferenceArrayField

Fetches multiple referenced records by an array of ids contained in the current record, and provides them through a ListContext to its children. Use it to display a list of related records, via a one-to-many relationship materialized by an array of foreign keys.

Installation

pnpm dlx shadcn@latest add @shadmin/reference-array-field

Usage

For instance, let's consider a model where a post has many tags, materialized to a tags_ids field containing an array of ids:

┌──────────────┐       ┌────────┐
│ posts        │       │ tags   │
│--------------│       │--------│
│ id           │   ┌───│ id     │
│ title        │   │   │ name   │
│ body         │   │   └────────┘
│ is_published │   │
│ tag_ids      │╾──┘
└──────────────┘

A typical post record therefore looks like this:

{
  "id": 1,
  "title": "Hello world",
  "body": "...",
  "tags_ids": [1, 2, 3]
}

In that case, use <ReferenceArrayField> to display the post tag names as follows:

import { List, DataTable, ReferenceArrayField } from "@/components/admin";
 
export const PostList = () => (
  <List>
    <DataTable>
      <DataTable.Col source="id" />
      <DataTable.Col source="title" />
      <DataTable.Col source="tag_ids" label="Tags">
        <ReferenceArrayField reference="tags" source="tag_ids" />
      </DataTable.Col>
      <DataTable.Col>
        <EditButton />
      </DataTable.Col>
    </DataTable>
  </List>
);

<ReferenceArrayField> fetches the tag resources related to each post resource by matching post.tag_ids to tag.id (using dataProvider.getMany()).

Configure the <Resource recordRepresentation> to render related records in a meaningful way. For instance, for the tags resource, if you want the <ReferenceArrayField> to display the tag name:

<Resource name="tags" list={TagList} recordRepresentation="name" />

<ReferenceArrayField> expects a reference attribute, which specifies the resource to fetch for the related records. It also expects a source attribute, which defines the field containing the list of ids to look for in the referenced resource.

Props

PropRequiredTypeDefaultDescription
sourceRequiredstring-Field with array of ids
referenceRequiredstring-Target resource name
childrenOptionalReactNode<SingleFieldList />Display component(s)
classNameOptionalstring-Wrapper classes
emptyOptionalReactNode-Placeholder when no data
errorOptionalReactNode-Error element (set false to hide)
filterOptionalobject-Permanent filters
loadingOptionalReactNode-Loading element (set false to hide)
offlineOptionalReactNode<Offline />Element rendered when the network is offline
pageOptionalnumber1Initial page
paginationOptionalReactNode-Pagination component
perPageOptionalnumber-Page size (default 1000 in code if unspecified)
queryOptionsOptionalUseQueryOptions-TanStack Query options
renderOptional(props: ListControllerResult<ReferenceRecordType>) => ReactElement-A function rendering the record list, receive the list context as its argument
resourceOptionalstringParent resourceOverride resource name
sortOptional{ field: string; order: 'ASC' | 'DESC' }-Sort order

Records Representation

By default, <ReferenceArrayField> renders one string by related record, via a <SingleFieldList> with a <BadgeField> child using the resource recordRepresentation as source.

You can change how the list of related records is rendered by passing a custom child reading the ListContext.

For instance, use a <DataTable> to render the related records in a table:

import {
  Show,
  TextField,
  ReferenceArrayField,
  DataTable,
} from "@/components/admin";
 
export const PostShow = () => (
  <Show>
    <div className="flex flex-col gap-4">
      <TextField source="id" />
      <TextField source="title" />
      <ReferenceArrayField label="Tags" reference="tags" source="tag_ids">
        <DataTable>
          <DataTable.Col source="id" />
          <DataTable.Col source="name" />
        </DataTable>
      </ReferenceArrayField>
      <EditButton />
    </div>
  </Show>
);

Alternatively, you can use the render prop to render the related records in a custom way:

import {
  Show,
  SimpleShowLayout,
  TextField,
  ReferenceArrayField,
} from "@/components/admin";
 
export const PostShow = () => (
  <Show>
    <SimpleShowLayout>
      <TextField source="id" />
      <TextField source="title" />
      <ReferenceArrayField
        label="Tags"
        reference="tags"
        source="tag_ids"
        render={({ data }) => (
          <ul>
            {data?.map((tag) => (
              <li key={tag.id}>{tag.name}</li>
            ))}
          </ul>
        )}
      />
      <EditButton />
    </SimpleShowLayout>
  </Show>
);

offline

Element rendered when the network is offline and the reference data is unavailable. Defaults to the inherited offline component from ra-core.

<ReferenceArrayField
  reference="tags"
  source="tag_ids"
  offline={
    <span className="text-muted-foreground italic">
      Offline — tags unavailable
    </span>
  }
/>

Tips

  • Use <ReferenceManyField> instead when you need to display records from another resource that reference the current record (inverse relationship).