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 a rich set of UI components including buttons, notifications, theming capabilities, and utility components. Built on Material-UI, these components ensure consistent design and excellent user experience across admin interfaces.
Base button component with React Admin styling and functionality.
import { Button } from 'react-admin';
interface ButtonProps {
label?: string;
children?: React.ReactNode;
color?: 'inherit' | 'primary' | 'secondary' | 'success' | 'error' | 'info' | 'warning';
disabled?: boolean;
size?: 'small' | 'medium' | 'large';
variant?: 'text' | 'outlined' | 'contained';
startIcon?: React.ReactNode;
endIcon?: React.ReactNode;
onClick?: (event: React.MouseEvent) => void;
href?: string;
to?: string;
className?: string;
sx?: any;
}
const Button: React.FC<ButtonProps>;Button for saving forms with loading states and validation.
import { SaveButton } from 'react-admin';
interface SaveButtonProps extends ButtonProps {
alwaysEnable?: boolean;
icon?: React.ReactElement;
invalid?: boolean;
mutationOptions?: UseMutationOptions;
pristine?: boolean;
saving?: boolean;
submitOnEnter?: boolean;
transform?: TransformData;
type?: 'button' | 'submit';
}
const SaveButton: React.FC<SaveButtonProps>;Buttons for deleting records with confirmation dialogs.
import { DeleteButton, DeleteWithConfirmButton } from 'react-admin';
interface DeleteButtonProps extends ButtonProps {
confirmTitle?: string;
confirmContent?: string | React.ReactElement;
icon?: React.ReactElement;
mutationMode?: 'pessimistic' | 'optimistic' | 'undoable';
mutationOptions?: UseMutationOptions;
record?: RaRecord;
redirect?: string | false | RedirectToFunction;
resource?: string;
translateOptions?: any;
}
const DeleteButton: React.FC<DeleteButtonProps>;
const DeleteWithConfirmButton: React.FC<DeleteButtonProps>;Buttons for navigating between views.
import {
CreateButton,
EditButton,
ShowButton,
ListButton,
CloneButton
} from 'react-admin';
interface CreateButtonProps extends ButtonProps {
icon?: React.ReactElement;
record?: RaRecord;
resource?: string;
scrollToTop?: boolean;
}
interface EditButtonProps extends ButtonProps {
icon?: React.ReactElement;
record?: RaRecord;
resource?: string;
scrollToTop?: boolean;
}
interface ShowButtonProps extends EditButtonProps {}
interface ListButtonProps extends EditButtonProps {}
interface CloneButtonProps extends EditButtonProps {}
const CreateButton: React.FC<CreateButtonProps>;
const EditButton: React.FC<EditButtonProps>;
const ShowButton: React.FC<ShowButtonProps>;
const ListButton: React.FC<ListButtonProps>;
const CloneButton: React.FC<CloneButtonProps>;import {
TopToolbar,
CreateButton,
ExportButton,
EditButton,
DeleteButton,
ShowButton,
SaveButton
} from 'react-admin';
// List actions
const PostListActions = () => (
<TopToolbar>
<CreateButton />
<ExportButton />
</TopToolbar>
);
// Show actions
const PostShowActions = () => (
<TopToolbar>
<EditButton />
<DeleteButton />
</TopToolbar>
);
// Custom button with navigation
const CustomButton = () => {
const redirect = useRedirect();
return (
<Button
label="Custom Action"
onClick={() => redirect('list', 'posts')}
color="primary"
variant="contained"
/>
);
};Buttons for performing actions on multiple selected records.
import {
BulkDeleteButton,
BulkDeleteWithConfirmButton,
BulkExportButton,
BulkUpdateButton
} from 'react-admin';
interface BulkActionProps {
label?: string;
icon?: React.ReactElement;
selectedIds?: Identifier[];
className?: string;
sx?: any;
}
interface BulkDeleteButtonProps extends BulkActionProps {
mutationMode?: 'pessimistic' | 'optimistic' | 'undoable';
mutationOptions?: UseMutationOptions;
}
interface BulkUpdateButtonProps extends BulkActionProps {
data: any;
mutationMode?: 'pessimistic' | 'optimistic' | 'undoable';
mutationOptions?: UseMutationOptions;
}
const BulkDeleteButton: React.FC<BulkDeleteButtonProps>;
const BulkDeleteWithConfirmButton: React.FC<BulkDeleteButtonProps>;
const BulkExportButton: React.FC<BulkActionProps>;
const BulkUpdateButton: React.FC<BulkUpdateButtonProps>;import { BulkDeleteButton, BulkUpdateButton, BulkExportButton } from 'react-admin';
const PostBulkActions = () => (
<>
<BulkUpdateButton
label="Publish Selected"
data={{ status: 'published' }}
mutationMode="optimistic"
/>
<BulkExportButton />
<BulkDeleteButton mutationMode="pessimistic" />
</>
);
const PostList = () => (
<List>
<Datagrid bulkActionButtons={<PostBulkActions />}>
<TextField source="title" />
<SelectField source="status" choices={statusChoices} />
</Datagrid>
</List>
);Hook for displaying notifications to users.
import { useNotify } from 'react-admin';
type NotificationType = 'info' | 'success' | 'warning' | 'error';
interface NotifyOptions {
type?: NotificationType;
messageArgs?: any;
undoable?: boolean;
autoHideDuration?: number;
multiline?: boolean;
anchorOrigin?: {
vertical: 'top' | 'bottom';
horizontal: 'left' | 'center' | 'right';
};
}
type NotifyFunction = (
message: string,
options?: NotifyOptions
) => void;
const useNotify: () => NotifyFunction;import { useNotify } from 'react-admin';
const MyComponent = () => {
const notify = useNotify();
const handleSuccess = () => {
notify('Record saved successfully', { type: 'success' });
};
const handleError = () => {
notify('An error occurred', {
type: 'error',
autoHideDuration: 6000
});
};
const handleWarning = () => {
notify('This action cannot be undone', {
type: 'warning',
multiline: true
});
};
const handleUndoable = () => {
notify('Post deleted', {
type: 'info',
undoable: true
});
};
return (
<div>
<button onClick={handleSuccess}>Success</button>
<button onClick={handleError}>Error</button>
<button onClick={handleWarning}>Warning</button>
<button onClick={handleUndoable}>Undoable</button>
</div>
);
};Component for displaying notification messages.
import { Notification } from 'react-admin';
interface NotificationProps {
className?: string;
sx?: any;
}
const Notification: React.FC<NotificationProps>;React Admin uses Material-UI's theming system with additional customizations.
import { useTheme } from 'react-admin';
const useTheme: () => [Theme, (theme: Theme) => void];
interface Theme {
palette: {
mode: 'light' | 'dark';
primary: PaletteColor;
secondary: PaletteColor;
error: PaletteColor;
warning: PaletteColor;
info: PaletteColor;
success: PaletteColor;
background: {
default: string;
paper: string;
};
text: {
primary: string;
secondary: string;
};
};
typography: Typography;
spacing: (factor: number) => number;
breakpoints: Breakpoints;
components?: ComponentsOverrides;
}React Admin includes several built-in themes.
import {
defaultTheme,
nanoTheme,
radiantTheme,
houseTheme
} from 'react-admin';
const defaultTheme: Theme;
const nanoTheme: Theme;
const radiantTheme: Theme;
const houseTheme: Theme;import { Admin, defaultTheme, radiantTheme } from 'react-admin';
import { createTheme } from '@mui/material/styles';
// Using predefined themes
const App = () => (
<Admin theme={radiantTheme} dataProvider={dataProvider}>
<Resource name="posts" list={PostList} />
</Admin>
);
// Custom theme
const customTheme = createTheme({
palette: {
mode: 'dark',
primary: {
main: '#1976d2',
},
secondary: {
main: '#dc004e',
},
background: {
default: '#121212',
paper: '#1e1e1e',
},
},
typography: {
fontFamily: 'Inter, sans-serif',
},
components: {
MuiButton: {
styleOverrides: {
root: {
borderRadius: 8,
},
},
},
},
});
const AppWithCustomTheme = () => (
<Admin theme={customTheme} dataProvider={dataProvider}>
<Resource name="posts" list={PostList} />
</Admin>
);Button for switching between light and dark themes.
import { ToggleThemeButton } from 'react-admin';
interface ToggleThemeButtonProps {
className?: string;
sx?: any;
}
const ToggleThemeButton: React.FC<ToggleThemeButtonProps>;Provider for theme context in custom layouts.
import { ThemeProvider } from 'react-admin';
interface ThemeProviderProps {
theme?: Theme;
children: React.ReactNode;
}
const ThemeProvider: React.FC<ThemeProviderProps>;Component for confirmation dialogs.
import { Confirm } from 'react-admin';
interface ConfirmProps {
isOpen: boolean;
title: string;
content?: string | React.ReactElement;
onConfirm: () => void;
onClose: () => void;
confirmColor?: 'primary' | 'secondary' | 'error' | 'warning' | 'info' | 'success';
ConfirmIcon?: React.ComponentType;
CancelIcon?: React.ComponentType;
className?: string;
sx?: any;
}
const Confirm: React.FC<ConfirmProps>;Progress indicator component.
import { LinearProgress } from 'react-admin';
interface LinearProgressProps {
className?: string;
sx?: any;
}
const LinearProgress: React.FC<LinearProgressProps>;Various loading state indicators.
import { Loading, LoadingIndicator, LoadingPage } from 'react-admin';
const Loading: React.FC<{ className?: string; sx?: any }>;
const LoadingIndicator: React.FC<{ className?: string; sx?: any }>;
const LoadingPage: React.FC<{ className?: string; sx?: any }>;Enhanced link component with React Router integration.
import { Link } from 'react-admin';
interface LinkProps {
to: string;
children: React.ReactNode;
className?: string;
sx?: any;
color?: 'inherit' | 'primary' | 'secondary' | 'textPrimary' | 'textSecondary' | 'error';
underline?: 'none' | 'hover' | 'always';
variant?: string;
}
const Link: React.FC<LinkProps>;Icon button for refreshing data.
import { RefreshIconButton } from 'react-admin';
const RefreshIconButton: React.FC<{ className?: string; sx?: any }>;Accessibility component for keyboard navigation.
import { SkipNavigationButton } from 'react-admin';
const SkipNavigationButton: React.FC<{ className?: string; sx?: any }>;Button for language selection.
import { LocalesMenuButton } from 'react-admin';
interface LocalesMenuButtonProps {
className?: string;
sx?: any;
languages?: { locale: string; name: string }[];
}
const LocalesMenuButton: React.FC<LocalesMenuButtonProps>;import { useState } from 'react';
import { Confirm, useDelete, useNotify, useRedirect } from 'react-admin';
const CustomDeleteButton = ({ record }) => {
const [open, setOpen] = useState(false);
const [deleteOne, { isLoading }] = useDelete();
const notify = useNotify();
const redirect = useRedirect();
const handleDelete = () => {
deleteOne('posts', { id: record.id, previousData: record })
.then(() => {
notify('Post deleted successfully');
redirect('list', 'posts');
})
.catch(() => {
notify('Error deleting post', { type: 'error' });
});
setOpen(false);
};
return (
<>
<Button
label="Delete"
onClick={() => setOpen(true)}
color="error"
/>
<Confirm
isOpen={open}
title="Delete Post"
content="Are you sure you want to delete this post? This action cannot be undone."
onConfirm={handleDelete}
onClose={() => setOpen(false)}
confirmColor="error"
/>
</>
);
};import { Chip } from '@mui/material';
import { useTheme } from '@mui/material/styles';
const StatusIndicator = ({ status }) => {
const theme = useTheme();
const getStatusColor = (status) => {
switch (status) {
case 'published': return theme.palette.success.main;
case 'draft': return theme.palette.warning.main;
case 'archived': return theme.palette.text.disabled;
default: return theme.palette.text.secondary;
}
};
return (
<Chip
label={status.toUpperCase()}
size="small"
sx={{
backgroundColor: getStatusColor(status),
color: 'white',
fontWeight: 'bold'
}}
/>
);
};import { Toolbar, SaveButton, Button } from 'react-admin';
import { useFormContext } from 'react-hook-form';
import { useNotify } from 'react-admin';
const CustomFormToolbar = () => {
const { reset, getValues } = useFormContext();
const notify = useNotify();
const handleSaveAndContinue = () => {
// Custom save logic
notify('Saved and continuing...');
};
const handleReset = () => {
reset();
notify('Form reset');
};
return (
<Toolbar>
<SaveButton />
<Button
label="Save & Continue"
onClick={handleSaveAndContinue}
variant="outlined"
sx={{ marginLeft: 1 }}
/>
<Button
label="Reset"
onClick={handleReset}
variant="text"
sx={{ marginLeft: 1 }}
/>
</Toolbar>
);
};import { useMediaQuery, useTheme } from '@mui/material';
import { TopToolbar, CreateButton, ExportButton, Button } from 'react-admin';
const ResponsiveActions = () => {
const theme = useTheme();
const isSmall = useMediaQuery(theme.breakpoints.down('sm'));
return (
<TopToolbar>
<CreateButton />
{!isSmall && <ExportButton />}
{!isSmall && (
<Button label="Advanced" onClick={() => {}} />
)}
</TopToolbar>
);
};import { useState } from 'react';
import { ToggleThemeButton, useTheme } from 'react-admin';
import { Menu, MenuItem, IconButton } from '@mui/material';
import { Palette as PaletteIcon } from '@mui/icons-material';
const ThemeSwitcher = () => {
const [theme, setTheme] = useTheme();
const [anchorEl, setAnchorEl] = useState(null);
const themes = [
{ name: 'Default', value: defaultTheme },
{ name: 'Nano', value: nanoTheme },
{ name: 'Radiant', value: radiantTheme },
{ name: 'House', value: houseTheme }
];
const handleClose = () => setAnchorEl(null);
const handleThemeSelect = (selectedTheme) => {
setTheme(selectedTheme);
handleClose();
};
return (
<>
<IconButton onClick={(e) => setAnchorEl(e.currentTarget)}>
<PaletteIcon />
</IconButton>
<Menu
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={handleClose}
>
{themes.map((themeOption) => (
<MenuItem
key={themeOption.name}
onClick={() => handleThemeSelect(themeOption.value)}
>
{themeOption.name}
</MenuItem>
))}
</Menu>
</>
);
};React Admin's UI component system provides a comprehensive set of building blocks for creating polished, accessible, and responsive admin interfaces with consistent design patterns and excellent user experience.
Install with Tessl CLI
npx tessl i tessl/npm-react-admin