A frontend Framework for building admin applications on top of REST services, using ES6, React and Material UI
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
React Admin provides powerful components for displaying and interacting with collections of data. The list system supports pagination, sorting, filtering, bulk actions, and various display formats from simple lists to complex data grids.
The <List> component is the main container for list views, handling data fetching, pagination, sorting, and filtering.
import { List } from 'react-admin';
interface ListProps {
title?: string | React.ReactElement;
actions?: React.ReactElement | false;
filters?: React.ReactElement;
pagination?: React.ReactElement | false;
perPage?: number;
sort?: { field: string; order: 'ASC' | 'DESC' };
filter?: any;
filterDefaultValues?: any;
disableSyncWithLocation?: boolean;
exporter?: Exporter | false;
bulkActionButtons?: React.ReactElement | false;
empty?: React.ReactElement;
emptyWhileLoading?: boolean;
children: React.ReactNode;
className?: string;
sx?: any;
resource?: string;
hasCreate?: boolean;
hasEdit?: boolean;
hasShow?: boolean;
aside?: React.ReactElement;
component?: React.ElementType;
queryOptions?: UseQueryOptions;
debounce?: number;
storeKey?: string | false;
}
const List: React.FC<ListProps>;import { List, Datagrid, TextField, DateField, EditButton } from 'react-admin';
const PostList = () => (
<List>
<Datagrid>
<TextField source="id" />
<TextField source="title" />
<DateField source="published_at" />
<EditButton />
</Datagrid>
</List>
);import {
List,
Datagrid,
TextField,
DateField,
BulkDeleteButton,
CreateButton,
ExportButton,
TopToolbar
} from 'react-admin';
const PostList = () => {
const PostListActions = () => (
<TopToolbar>
<CreateButton />
<ExportButton />
</TopToolbar>
);
const PostBulkActions = () => (
<>
<BulkDeleteButton />
</>
);
return (
<List
title="Blog Posts"
actions={<PostListActions />}
bulkActionButtons={<PostBulkActions />}
sort={{ field: 'published_at', order: 'DESC' }}
perPage={25}
filters={<PostFilter />}
>
<Datagrid>
<TextField source="title" />
<TextField source="author" />
<DateField source="published_at" />
<EditButton />
</Datagrid>
</List>
);
};The <Datagrid> component displays data in a table format with sorting, selection, and row actions.
import { Datagrid } from 'react-admin';
interface DatagridProps {
body?: React.ComponentType<DatagridBodyProps>;
row?: React.ComponentType<DatagridRowProps>;
rowStyle?: Function;
rowSx?: Function;
rowClick?: string | Function | false;
isRowSelectable?: Function;
isRowExpandable?: Function;
expand?: React.ReactElement;
expandSingle?: boolean;
bulkActionButtons?: React.ReactElement | false;
hover?: boolean;
size?: 'small' | 'medium';
empty?: React.ReactElement;
optimized?: boolean;
children: React.ReactNode;
className?: string;
sx?: any;
}
const Datagrid: React.FC<DatagridProps>;import { Datagrid, TextField, BooleanField, DateField, ShowButton, EditButton } from 'react-admin';
const ProductDatagrid = () => (
<Datagrid
rowClick="edit"
bulkActionButtons={<BulkActionsToolbar />}
expand={<ProductDetail />}
isRowSelectable={record => record.published}
rowSx={record => ({
backgroundColor: record.featured ? '#ffe' : 'inherit'
})}
>
<TextField source="name" />
<TextField source="category" />
<BooleanField source="published" />
<DateField source="created_at" />
<ShowButton />
<EditButton />
</Datagrid>
);Field components display individual data values within lists and detail views.
Display text and string values.
import { TextField } from 'react-admin';
interface FieldProps {
source: string;
label?: string | false;
sortable?: boolean;
sortBy?: string;
className?: string;
cellClassName?: string;
headerClassName?: string;
textAlign?: 'left' | 'right' | 'center';
emptyText?: string;
sx?: any;
sortByOrder?: 'ASC' | 'DESC';
}
const TextField: React.FC<FieldProps>;Display numeric values with formatting.
import { NumberField } from 'react-admin';
interface NumberFieldProps extends FieldProps {
locales?: string | string[];
options?: Intl.NumberFormatOptions;
}
const NumberField: React.FC<NumberFieldProps>;// Basic number field
<NumberField source="price" />
// Currency formatting
<NumberField
source="price"
options={{
style: 'currency',
currency: 'USD'
}}
/>
// Percentage formatting
<NumberField
source="discount"
options={{
style: 'percent',
minimumFractionDigits: 2
}}
/>Display dates with localization and formatting.
import { DateField } from 'react-admin';
interface DateFieldProps extends FieldProps {
showTime?: boolean;
locales?: string | string[];
options?: Intl.DateTimeFormatOptions;
transform?: (value: any) => Date;
}
const DateField: React.FC<DateFieldProps>;// Date only
<DateField source="created_at" />
// Date and time
<DateField source="updated_at" showTime />
// Custom format
<DateField
source="published_at"
options={{
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
}}
/>Display boolean values as icons or text.
import { BooleanField } from 'react-admin';
interface BooleanFieldProps extends FieldProps {
valueLabelTrue?: string;
valueLabelFalse?: string;
TrueIcon?: React.ComponentType;
FalseIcon?: React.ComponentType;
}
const BooleanField: React.FC<BooleanFieldProps>;Display email addresses as clickable mailto links.
import { EmailField } from 'react-admin';
const EmailField: React.FC<FieldProps>;Display URLs as clickable links.
import { UrlField } from 'react-admin';
const UrlField: React.FC<FieldProps>;Display images from URLs.
import { ImageField } from 'react-admin';
interface ImageFieldProps extends FieldProps {
src?: string;
title?: string;
alt?: string;
}
const ImageField: React.FC<ImageFieldProps>;Display files as download links.
import { FileField } from 'react-admin';
interface FileFieldProps extends FieldProps {
src?: string;
title?: string;
target?: string;
}
const FileField: React.FC<FileFieldProps>;Display values as Material-UI chips.
import { ChipField } from 'react-admin';
interface ChipFieldProps extends FieldProps {
size?: 'small' | 'medium';
variant?: 'filled' | 'outlined';
color?: 'default' | 'primary' | 'secondary';
clickable?: boolean;
onClick?: Function;
}
const ChipField: React.FC<ChipFieldProps>;Display choice values with labels.
import { SelectField } from 'react-admin';
interface SelectFieldProps extends FieldProps {
choices: ChoiceType[];
optionText?: string | Function;
optionValue?: string;
translateChoice?: boolean;
}
const SelectField: React.FC<SelectFieldProps>;Display array values in various formats.
import { ArrayField } from 'react-admin';
interface ArrayFieldProps extends FieldProps {
children?: React.ReactElement;
}
const ArrayField: React.FC<ArrayFieldProps>;<ArrayField source="tags">
<SingleFieldList>
<ChipField source="name" />
</SingleFieldList>
</ArrayField>Display computed values using a custom function.
import { FunctionField } from 'react-admin';
interface FunctionFieldProps extends Omit<FieldProps, 'source'> {
render: (record: RaRecord, source?: string) => any;
source?: string;
}
const FunctionField: React.FC<FunctionFieldProps>;<FunctionField
label="Full Name"
render={record => `${record.firstName} ${record.lastName}`}
/>
<FunctionField
label="Total"
render={record => record.quantity * record.price}
/>Display values from referenced records.
import { ReferenceField } from 'react-admin';
interface ReferenceFieldProps extends FieldProps {
reference: string;
children: React.ReactElement;
link?: string | Function | false;
queryOptions?: UseQueryOptions;
}
const ReferenceField: React.FC<ReferenceFieldProps>;<ReferenceField source="categoryId" reference="categories" link="show">
<TextField source="name" />
</ReferenceField>
<ReferenceField source="authorId" reference="users" link={false}>
<FunctionField render={record => `${record.firstName} ${record.lastName}`} />
</ReferenceField>Display multiple referenced records.
import { ReferenceArrayField } from 'react-admin';
interface ReferenceArrayFieldProps extends FieldProps {
reference: string;
children: React.ReactElement;
sort?: { field: string; order: 'ASC' | 'DESC' };
filter?: any;
perPage?: number;
}
const ReferenceArrayField: React.FC<ReferenceArrayFieldProps>;<ReferenceArrayField source="tagIds" reference="tags">
<SingleFieldList>
<ChipField source="name" />
</SingleFieldList>
</ReferenceArrayField>Display records that reference the current record.
import { ReferenceManyField } from 'react-admin';
interface ReferenceManyFieldProps extends FieldProps {
reference: string;
target: string;
children: React.ReactElement;
sort?: { field: string; order: 'ASC' | 'DESC' };
filter?: any;
perPage?: number;
pagination?: React.ReactElement;
}
const ReferenceManyField: React.FC<ReferenceManyFieldProps>;<ReferenceManyField
label="Comments"
reference="comments"
target="postId"
sort={{ field: 'created_at', order: 'DESC' }}
>
<Datagrid>
<TextField source="author" />
<TextField source="body" />
<DateField source="created_at" />
</Datagrid>
</ReferenceManyField>Simple list layout for mobile-friendly displays.
import { SimpleList } from 'react-admin';
interface SimpleListProps {
primaryText?: string | Function;
secondaryText?: string | Function;
tertiaryText?: string | Function;
leftAvatar?: string | Function | React.ReactElement;
leftIcon?: string | Function | React.ReactElement;
rightAvatar?: string | Function | React.ReactElement;
rightIcon?: string | Function | React.ReactElement;
linkType?: string | Function | false;
rowStyle?: Function;
rowSx?: Function;
className?: string;
sx?: any;
}
const SimpleList: React.FC<SimpleListProps>;<List>
<SimpleList
primaryText={record => record.title}
secondaryText={record => `${record.views} views`}
tertiaryText={record => new Date(record.published_at).toLocaleDateString()}
linkType="show"
/>
</List>Display a single field for each record.
import { SingleFieldList } from 'react-admin';
interface SingleFieldListProps {
linkType?: string | Function | false;
children: React.ReactElement;
className?: string;
sx?: any;
}
const SingleFieldList: React.FC<SingleFieldListProps>;List with infinite scrolling.
import { InfiniteList } from 'react-admin';
const InfiniteList: React.FC<ListProps>;import { Filter, SearchInput, SelectInput, DateInput } from 'react-admin';
const PostFilter = () => (
<Filter>
<SearchInput source="q" alwaysOn />
<SelectInput
source="status"
choices={[
{ id: 'published', name: 'Published' },
{ id: 'draft', name: 'Draft' }
]}
/>
<DateInput source="published_since" />
</Filter>
);import { List, Datagrid, Filter, TextInput, ReferenceInput, SelectInput } from 'react-admin';
const PostFilter = () => (
<Filter>
<TextInput label="Search" source="q" alwaysOn />
<ReferenceInput source="categoryId" reference="categories" allowEmpty>
<SelectInput optionText="name" />
</ReferenceInput>
<SelectInput
source="status"
choices={[
{ id: 'published', name: 'Published' },
{ id: 'draft', name: 'Draft' },
{ id: 'rejected', name: 'Rejected' }
]}
/>
</Filter>
);
const PostList = () => (
<List filters={<PostFilter />}>
<Datagrid>
<TextField source="title" />
<TextField source="status" />
<DateField source="published_at" />
</Datagrid>
</List>
);import { Pagination } from 'react-admin';
interface PaginationProps {
rowsPerPageOptions?: number[];
showFirstButton?: boolean;
showLastButton?: boolean;
className?: string;
sx?: any;
}
const Pagination: React.FC<PaginationProps>;<List pagination={<Pagination rowsPerPageOptions={[10, 25, 50, 100]} />}>
<Datagrid>
<TextField source="title" />
</Datagrid>
</List>import {
BulkDeleteButton,
BulkUpdateButton,
BulkExportButton
} from 'react-admin';
const BulkActionsToolbar = () => (
<>
<BulkDeleteButton />
<BulkUpdateButton
data={{ published: true }}
label="Publish Selected"
/>
<BulkExportButton />
</>
);import { Button, useListContext, useUnselectAll } from 'react-admin';
const BulkArchiveButton = () => {
const { selectedIds } = useListContext();
const unselectAll = useUnselectAll('posts');
const handleArchive = () => {
// Archive selected records
console.log('Archiving:', selectedIds);
unselectAll();
};
return (
<Button
label="Archive"
onClick={handleArchive}
disabled={selectedIds.length === 0}
/>
);
};Access list state and methods.
import { useListContext } from 'react-admin';
const useListContext: () => {
data: RaRecord[];
isLoading: boolean;
error: any;
total: number;
page: number;
perPage: number;
setPage: (page: number) => void;
setPerPage: (perPage: number) => void;
setSort: (sort: { field: string; order: 'ASC' | 'DESC' }) => void;
setFilters: (filters: any, displayedFilters?: any) => void;
showFilter: (filterName: string, defaultValue?: any) => void;
hideFilter: (filterName: string) => void;
filterValues: any;
displayedFilters: any;
selectedIds: Identifier[];
onSelect: (ids: Identifier[]) => void;
onToggleItem: (id: Identifier) => void;
onUnselectItems: () => void;
sort: { field: string; order: 'ASC' | 'DESC' };
resource: string;
refetch: () => void;
};import { List, Empty } from 'react-admin';
const CustomEmpty = () => (
<Empty>
<h2>No posts yet</h2>
<p>Create your first post to get started</p>
<CreateButton />
</Empty>
);
const PostList = () => (
<List empty={<CustomEmpty />}>
<Datagrid>
<TextField source="title" />
</Datagrid>
</List>
);import { List, Datagrid, TextField, useRecordContext } from 'react-admin';
const PostPanel = () => {
const record = useRecordContext();
return (
<div style={{ padding: 16 }}>
<strong>Description:</strong> {record.description}
</div>
);
};
const PostList = () => (
<List>
<Datagrid expand={<PostPanel />} expandSingle>
<TextField source="title" />
<TextField source="author" />
<DateField source="published_at" />
</Datagrid>
</List>
);<Datagrid
rowSx={record => ({
backgroundColor: record.published ? '#e8f5e8' : '#fff2e8',
'&:hover': {
backgroundColor: record.published ? '#d4f5d4' : '#ffe4cc'
}
})}
isRowSelectable={record => !record.archived}
>
<TextField source="title" />
<BooleanField source="published" />
</Datagrid>import { List, SimpleList, Datagrid, useMediaQuery } from 'react-admin';
const PostList = () => {
const isSmall = useMediaQuery((theme: any) => theme.breakpoints.down('sm'));
return (
<List>
{isSmall ? (
<SimpleList
primaryText={record => record.title}
secondaryText={record => `By ${record.author}`}
tertiaryText={record => new Date(record.published_at).toLocaleDateString()}
/>
) : (
<Datagrid>
<TextField source="title" />
<TextField source="author" />
<DateField source="published_at" />
<EditButton />
</Datagrid>
)}
</List>
);
};React Admin's list and data display system provides comprehensive functionality for presenting collections of data in various formats, with powerful filtering, sorting, and interaction capabilities that scale from simple lists to complex data management interfaces.
Install with Tessl CLI
npx tessl i tessl/npm-react-admin